欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

双重锁检测单例模式中volatile的理解

程序员文章站 2022-03-11 18:31:46
...
public static Singleton getInstance() {  
        if (instance == null) {  
            synchronized (Singleton.class) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }

这种情况下,会有风险,是指令重排序导致的问题

instance = new Singleton(),正常的指令顺序是:

  1. memory = allocate();   //1:分配对象的内存空间  
  2. ctorInstance(memory);  //2:初始化对象  
  3. instance = memory;     //3:设置instance指向刚分配的内存地址  

但是经过重排序后如下:

  1. memory = allocate();   //1:分配对象的内存空间  
  2. instance = memory;     //3:设置instance指向刚分配的内存地址  
  3.                        //注意,此时对象还没有被初始化!  
  4. ctorInstance(memory);  //2:初始化对象 

将第2步和第3步调换顺序,在单线程情况下不会影响程序执行的结果,但是在多线程情况下就不一样了。线程A执行了instance = memory(这对另一个线程B来说是可见的),此时线程B执行外层 if (instance == null),发现instance不为空,随即返回,但是得到的却是未被完全初始化的实例,有人说synchronized不是可以禁止重排序吗?这只是假象,是因为不加锁后是单线程,这种情况下无论重排序或者不重排序,结果都是一样的,synchronized并不是禁止了重排序,而是即使重排序,也不影响其结果!

相关标签: 技术点