zoukankan      html  css  js  c++  java
  • 延迟初始化对象的错误用法:双重检查锁定

    双重检查锁定的设想:

    1. 多个线程试图在同一时间创建对象,会通过加锁来保证只有一个线程能创建对象
    2. 在对象创建好后,执行 getInstance() 方法将不需要获取锁,直接返回已创建好的对象

    对于 Instance 类,以下是双重检查锁定代码

    public class DoubleCheckedLocking {
        private static Instance instance;
    
        public static Instance getInstance() {
            // 第一次检查
            if (instance == null) {
                // 加锁
                synchronized (DoubleCheckedLocking.class) {
                    // 第二次检查
                    if (instance == null) {
                        // 问题的根源
                        instance = new Instance();
                    }
                }
            }
    
            return instance;
        }
    }
    

    问题:

    第一次检查时,代码读取到 instance 不为 null 时,instance 引用的对象有可能还没有完成初始化。

    根源:

    上面的问题根源代码行

    instance = new Instance();
    

    可以拆解为以下 3 行伪代码:

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

    上述代码的 2 和 3 之间,可能会存在重排序。发生重排序后的执行时序如下:

    // 1.分配对象的内存空间
    memory = allocate();
    // 3.设置 instance 指向刚分配的内存地址
    instance = momory;
    // 2.初始化对象
    ctorInstance(memory);
    
    单线程执行时序图

    2 和 3 虽然重排序了,但并不违反规则,只要保证 2 在 4 前面就可以保证结果不变
    在这里插入图片描述

    多线程执行时序图

    当在初始化时,B 线程会看到一个还没有被初始化的对象。
    在这里插入图片描述

    结论

    如果在

    instance = new Instance();
    

    发生重排序,另一个并发线程 B 就有可能在第一次判断时不为 null,B将会访问 instance 所引用的对象,但此时这个对象可能还没有被 A 线程初始化。

    没有修不好的电脑
  • 相关阅读:
    MySQL------代码1024,can't get hostname for your address解决方法
    MySQL------存储过程的使用
    MyEclipse------如何添加jspsmartupload.jar,用于文件上传
    JQuery------实现鼠标点击和滑动不同效果
    CSS------如何让div中的div处于右下角
    JQuery------制作div模态框
    CSS------Filter属性的使用方法
    python使用元类
    python __new__()分析
    centos自带python2.6升级到python2.7。并解决yum pip easy_install pip等模块兼容性问题
  • 原文地址:https://www.cnblogs.com/duniqb/p/12702440.html
Copyright © 2011-2022 走看看