双重检查锁与延迟初始化

public class UnsafeLazyInitialization {

    private static Instance instance;

    public static Instance getInstance() {

        if(instance == null) {                            //A线程执行

            instance = new Instance();             //B线程执行

        }

        return instance;

}                                    

public class UnsafeLazyInitialization {

    private static Instance instance;

    public synchronized static Instance getInstance() {

        if(instance == null) {                            //A线程执行

            instance = new Instance();             //B线程执行

        }

        return instance;

}          

public class DoubleCheckedLocking {

    private static Instance instance;

    public static Instance getInstance() {

        if (instance == null) {                                                        // 1:第一次检查

            synchronized  (DoubleCheckedLocking.class) {        // 2:加锁

                if(instance == null) {                                                  // 3:第二次检查

                    instance = new Instance();                                    // 4:问题的根源出在这里

                }

            }

        }

        return instance;

    }         

    如上面代码所示,如果第一次检查instance不为null那么就不需要执行下面的加锁和初始化操作。因此,可以大幅降低synchronized带来的性能开销。但是在线程执行到1的时候,代码读取到instance不为null时,instance引用的对象有可能还没有完成初始化:

    示例代码的4(instance = new Instance())创建了一个对象。这一行代码可以分解为如下的三行伪代码。

        memory = allocate();             // 1:分配对象的内存空间

        ctorInstance(memory);          // 2:初始化对象

        instance = memory;              // 3:设置instance指向刚分配的内存地址

    上面伪代码中的2和3,可能会被重排序。


多线程执行时序表

    解决方案:

    1、不允许2和3重排序

        用volatile修饰instance,禁止重排序

  public class DoubleCheckedLocking {

    private volatile static Instance instance;

    public static Instance getInstance() {

            if (instance == null) {                                                        // 1:第一次检查

             synchronized  ( DoubleCheckedLocking.class) {        // 2:加锁

                if(instance == null) {                                                  // 3:第二次检查

                    instance = new Instance();                                    // 4:问题的根源出在这里

                }

            }

        }

        return instance;

    }         


    2、允许2和3重排序,但不允许其他线程“看到”这个重排序

    基于类初始化,JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。(参看初始化类)

    public class InstanceFactory {

        private static class InstanceHolder{

            public static Instance instance = new Instance();

        }

        public static Instance getInstance() {

            return InstanceHolder.instance;                //这里InstanceHolder类被初始化

        }

    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容