【问题标题】:Why use double checked locking为什么要使用双重检查锁定
【发布时间】:2015-10-30 03:03:12
【问题描述】:

关于我提出的previous question

    public static Singleton getInstanceDC() {
    if (_instance == null) {                // Single Checked (1)
        synchronized (Singleton.class) {
            if (_instance == null) {        // Double checked (2)
                _instance = new Singleton();
            }
        }
    }
    return _instance;

}

为什么要使用第二个实例空检查条件。可能会产生什么影响?

【问题讨论】:

    标签: java double-checked-locking


    【解决方案1】:

    让我们对行数进行编号,以便了解线程如何交错操作。

    if (_instance == null) {                // L1
        synchronized (Singleton.class) {    // L2
            if (_instance == null) {        // L3
                _instance = new Singleton();// L4
            }
        }
    }
    

    让我们考虑一个不检查 L3 的交错。

    1. 线程 1 到达 L1 并且 _instancenull
    2. 线程 2 到达 L1 并且 _instancenull
    3. 线程 1 在 L2 获得互斥体
    4. 线程 2 尝试在 L2 获取互斥体但阻塞
    5. 线程 1 创建新实例并在 L4 分配
    6. 线程 1 从 L2 释放互斥锁
    7. 线程 2 在 L2 获得互斥锁
    8. 线程 2 创建新实例并在 L4 分配
    9. 线程 2 从 L2 释放互斥锁

    Singleton 创建了两个实例。每个线程都返回自己的实例。

    通过 L3 的检查,第 8 步不会发生,因为在第 7 步线程 2 的 _instance 视图已与线程 1 同步,因此只创建了一个 Singleton 实例。

    【讨论】:

    • 我的多线程已经很生疏了,但是我们不能让整个方法同步并去掉方法内部的额外检查吗?
    • 您可以这样做,但即使对象已经创建,也意味着要获得锁,因此效率不高。通过仔细检查,我们确保如果对象已经创建,您不必等待(等待锁定)来获取它。
    • @turingcomplete,您可以使用inner class 解决方案来避免每次获取锁定,而是依赖于类加载器中隐含的锁定,在成功加载后通过代码重写将其删除。
    猜你喜欢
    • 2011-12-12
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多