public class SingletonDemo {
public static SingletonDemo instance = null;
private SingletonDemo() {
System.out.println("我是构造方法");
}
private static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo.class) {
if (instance==null){
instance = new SingletonDemo();
}
}
}
return instance;
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() -> {
instance = SingletonDemo.getInstance();
});
}
executorService.shutdown();
}
双端检索机制的隐患 从上面的结果我们可以看出来,好像加了双端检索机制貌似就没有出现问题啦, 而且运行检验的时候,他的确是只输出了一次构造方法吗? 但是问题真的就这么解决了吗?
DCL(双端检索机制)机制不一定安全,因为有指令重排的存在,加入voliate则可以禁止指令重排 原因是在某个线程执行到第一次检测,读取到instance为null的时候,instance对象没有完成对象的初始化,而 instance = new SingletonDemo();又可以分为三步 memory = allocate() 分配内存空间 语句1 instance(memory ) 初始化对象 语句2 instance = memory 实例指向内空间 语句3 因为语句2和语句3没有数据依赖性,所以 他们的顺序可以指令重排, 如果为132顺序的话.在对象还没有完成对象的初始化的时候,直接把null的对象指向内存空间,会导致出现null的结果
解决双端检索机制的隐患
public static volatile SingletonDemo instance = null;
private SingletonDemo() {
System.out.println("我是构造方法");
}
private static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo.class) {
if (instance==null){
instance = new SingletonDemo();
}
}
}
return instance;
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executorService.submit(() -> {
instance = SingletonDemo.getInstance();
});
}
executorService.shutdown();
}