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 线程初始化。

    没有修不好的电脑
  • 相关阅读:
    android购物车的实现
    eclipse配置maven
    Android 高仿微信实时聊天 基于百度云推送
    如何使用Ubuntu online account API创建微博HTML5申请书
    C#创建和初始化类
    一个小的日常实践——距离阵列
    文本框中输入极限
    java阅读器hdfs单纯demo
    错误和问题解决的成本
    选择用户-保存选定的用户
  • 原文地址:https://www.cnblogs.com/duniqb/p/12702440.html
Copyright © 2011-2022 走看看