代码之家  ›  专栏  ›  技术社区  ›  tanyehzheng

信号量可以安全地使用双重检查锁定习惯用法吗?

  •  3
  • tanyehzheng  · 技术社区  · 14 年前

    以下代码在java中是否安全?

    public class TestDCL{
        private static final Semaphore lock = new Semaphore(1);
        private Object instance;
    
        public Object m(){
            if(instance == null){
                lock.acquire();
                if(instance == null){
                    instance = new Object();
                }
                lock.release();
            }
            return instance; 
        }
    }
    
    3 回复  |  直到 13 年前
        1
  •  0
  •   Tim Bender    14 年前

    答案是,这取决于。是你的吗 instance 可变的还是不变的?如果 包含可变状态,则必须将其声明为 volatile . 必须这样做的原因与@Vijay Mathew建议的部分构造对象无关,而是与线程可见性有关。对一个线程中的单实例状态所做的更改不一定对另一个线程可见。使用 不稳定的 关键字确保硬件将使用某种机制刷新缓存以消除过时数据。

    Java并发在实践中,第16.2.3章概述了安全的初始化习惯用法,并包含一个惰性的初始化习惯用法。16.2.4讨论双重检查锁定习语。

        2
  •  2
  •   Vijay Mathew Chor-ming Lung    14 年前

    这不是线程安全的。声明 new Object(); instance 不再是 null 当为它分配内存时。到达第一个线程的新线程 if 分配内存后的条件 实例 Bill Pugh's solution 既安全又懒惰。

        3
  •  1
  •   Toby Daniel C. Sobral    14 年前

    同意蒂姆以前的帖子。Volatile使得可视性和双重检查锁定的原因被描述为 clever but broken 围绕部分构造的对象(缓存一致性/JVM优化)。

    正如Tim所建议的,这都在Goetz的书中,但我想提出一个关于惰性初始化的观点。为什么这么做?在我的经验中,它一般不需要,而且您运行在多线程上下文中,并且真正关心初始化安全性——您引入了很多的变异性和复杂性,这是很难测试的。