双重检查锁定模式:是否破碎?

fas*_*ava 9 java concurrency singleton double-checked-locking

为什么模式被认为是破碎的?它看起来很好吗?有任何想法吗?

public static Singleton getInst() {
    if (instace == null) createInst();
    return instace;
}

private static synchronized createInst() {
     if (instace == null) {
         instace = new Singleton(); 
     }
}
Run Code Online (Sandbox Code Playgroud)

Jer*_*erg 21

乍一看看起来还不错,但这种技术有许多微妙的问题,通常应该避免.例如,请考虑以下事件序列:

  1. 线程A注意到该值未初始化,因此它获得锁定并开始初始化该值.
  2. 在A完成初始化之前,允许编译器生成的代码更新共享变量以指向部分构造的对象.
  3. 线程B注意到共享变量已初始化(或显示),并返回其值.因为线程B认为该值已经初始化,所以它不会获得锁定.如果B在B看到A完成的所有初始化之前使用该对象,则程序可能会崩溃.

您可以通过使用"volatile"关键字来正确处理单例实例来避免这种情况

  • +1 - 指出Java中双重检查锁定模式问题的唯一答案!! (2认同)

Mic*_*rdt 11

整个讨论是一个巨大的,无休止的脑时间浪费.99.9%的时间,单身人士没有任何重大的设置成本,并且没有任何理由设计设置来实现非同步保证延迟加载.

这就是你在Java中编写Singleton的方法:

public class Singleton{
    private Singleton instance = new Singleton();
    private Singleton(){ ... }
    public Singleton getInstance(){ return instance; }
}
Run Code Online (Sandbox Code Playgroud)

更好的是,让它成为一个枚举:

public enum Singleton{
    INSTANCE;
    private Singleton(){ ... }
}
Run Code Online (Sandbox Code Playgroud)


nkr*_*1pt 7

我不知道它是否被破坏,但由于同步这是相当昂贵的,它不是真正最有效的解决方案.更好的方法是使用'Initialization On Demand Holder Idiom',它在第一次需要时将你的单例加载到内存中,顾名思义,因此延迟加载.使用这个习惯用语最大的好处是你不需要同步,因为JLS确保类加载是串行的.

有关该主题的详细维基百科条目:http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

要记住的另一件事是,由于Spring和Guice之类的依赖注入框架已经出现,这些容器创建和管理类实例,如果需要它们将为您提供Singleton,因此不值得打破你的头脑除此之外,除非你想学习模式背后的想法,这是有用的.另请注意,这些IOC容器提供的单例是每个容器实例的单例,但通常每个应用程序都有一个IOC容器,因此它不会成为问题.


ata*_*man 6

问题如下:您的JVM可能会重新排序您的代码,并且字段对于不同的线程并不总是相同.看看这个:http://www.ibm.com/developerworks/java/library/j-dcl.html.使用volatile关键字应该解决这个问题,但它在java 1.5之前就已经破了.

大多数情况下单次检查锁定的速度已经足够快,请尝试以下方法:

// single checked locking: working implementation, but slower because it syncs all the time
public static synchronized Singleton getInst() {
    if (instance == null) 
        instance = new Singleton();
    return instance;
}
Run Code Online (Sandbox Code Playgroud)

另请参阅有效的java,在这里您可以找到关于此主题的精彩章节.

总结一下:不要做双重检查锁定,有更好的idoms.