线程绝对安全下的单例模式
想要保证线程安全,基本的操作就是加锁,只让一个线程操作同享数据,其他线程进行等待,我们可以采用同步方法,同步代码块,等等,最受关注的DCL双重检查
class singleton {
private singleton() {
}
private static singleton instance = null;
public static singleton getInstance() {
if (instance == null) {
synchronized (singleton.class) {
if (instance == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new singleton();
}
}
}
return instance;
}
}
双重检查是否真的一定绝对安全呢,答案是不一定
通过这个加载的字节码文件我们可以看到
instance = new singleton();
这行代码他是调用空参构造器进行创建对象,也就是我们图片看到的init方法,创建一个对象的过程的最后一步才是初始化实例完成。看修改后的代码:
class singleton {
private singleton() {
}
//2.如果在没有执行init方法前instance已经被创建,这时有一个线程进来判断instance并不为null
//这时他直接将还没有初始化成功的instance实例返回出去,这就是指令重排问题。
//3.避免指令重排,在声明instance变量是加上volatile关键字即可
private static volatile singleton instance = null;
public static singleton getInstance() {
if (instance == null) {
synchronized (singleton.class) {
if (instance == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//1.创建对象的步骤其实分为很多步骤,而构造器的init方法是最后完成的。
instance = new singleton();
}
}
}
return instance;
}
}
配合代码注释我相信你已经明白了DCL下的线程安全问题如果解决了😄😄