1.单例模式
- 懒汉模式 :线程不安全,多线程下可能new多个Test类。
public class Test {
private Test() {
}
private static Test instance = null;
public static Test getInstance() {
if (instance == null) {
instance = new Test();
}
return instance;
}
}
- 饿汉模式 :线程安全,但是当类加载时,就new实例对象了,不符合懒加载模式。
public class Test {
private Test() {
}
private static Test instance = new Test();
public static Test getInstance() {
return instance;
}
}
- 懒汉模式-加锁 :线程安全,方法上加锁严重影响性能。第二次直接取instance值都加锁了。
public class Test {
private Test() {
}
private static Test instance = null;
public static synchronized Test getInstance() {
if (instance == null) {
instance = new Test();
}
return instance;
}
}
- 懒汉模式-双重锁机制 :线程不安全。由于指令重排。
public class Test {
private Test() {
}
private static Test instance = null;
public static Test getInstance() {
if (instance == null) { // 双重检测机制
synchronized (Test.class) {
if (instance == null) {
instance = new Test();
}
}
}
return instance;
}
}
instance = new Test()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
1. 给 instance 分配堆内存(Test 对象)
2. 调用 Test的构造函数来初始化成员变量,形成实例
3. 将instance 指针 指向分配的内存空间(执行完这步 singleton才是非 null了)。
正常执行顺序:1->2->3,由于操作2和操作3没有依赖性(操作1和操作3有依赖性),可能发生指令重排,可能的执行顺序为:1->3->2。
回到代码,当操作1,3执行后,instnce指针是不为null了,此时,另一个线程执行 if(instance == null) 就会不成立,直接返回,而此时,Single的构造还可能未执行,会引发严重数据错误!!!!
- 懒汉模式-双重锁机制+volatile:线程安全。volatile禁止了指令重排。
public class Test {
private Test() {
}
private volatile static Test instance = null;
public static Test getInstance() {
if (instance == null) { // 双重检测机制
synchronized (Test.class) {
if (instance == null) {
instance = new Test();
}
}
}
return instance;
}
}
- 枚举单利:线程安全。最优解。
public class Test {
private Test() {
}
public static Test getInstance() {
return Singleton.INSTANE.getIntance();
}
private enum Singleton {
INSTANE;
private Test singleton;
Singleton() {
singleton = new Test();
}
public Test getIntance() {
return singleton;
}
}
}