双重锁定 - 它在地球上的Java中工作吗?

时间:2012-06-29 11:55:27

标签: java multithreading singleton

所有

这是着名的文章:

The "Double-Checked Locking is Broken" Declaration

它声明模式在Java中不起作用。它接着说,新的JVM可以通过使用volatile来使模式工作。

但是,在另一篇文章中:Memory Barriers and JVM Concurrency

它表示关键字“synchronized”会生成内存屏障全屏障。那么谁是对的?该模式是否适用于地球上的Java?

4 个答案:

答案 0 :(得分:4)

基本上有3种方法可以修复双重检查锁定:

  • 确保变量声明为 volatile (从Java 5起开始工作);

  • 首先只是不要理会:只是使用同步,不要试图弄乱花哨的bug - 而且可能毫无意义 - 手段“避免”它;

  • 类加载器为您执行同步。

我发布了example code here

BUT:双重检查锁定确实是一种过时的范例,如果它确实在Java中有用的话。正如我所看到的那样,C程序员基本上把它转移到了Java中,他们并没有完全理解JVM有效地处理类加载器中内置的问题的有效(和正确!)方式,并且同步的优化是通常最好在JVM级别制作。

我看到很多人用这种“模式”弄乱了他们的代码。我认为我没有看到任何实际数据表明它有任何好处。

另外:如果你确实有一个大型应用程序遇到了同步问题,那么Java的整个 raisons d'être就是它拥有丰富的并发库。看看你如何重新使用你的应用程序来使用它们......如果分析数据证明它是必要的。

答案 1 :(得分:1)

这取决于您使用的java版本。 这已在java 5和forward中修复。

检查http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java

答案 2 :(得分:0)

他们都是对的,DCL从5开始在Java中运行良好。

如果您希望程序在每次给定完全相同的输入时生成完全相同的输出,并且您使用DCL,则可能需要认真重新考虑您正在做的事情。可怕的很多可能取决于谁首先进入锁定 - 你滚动了很多骰子。不适合会计应用。

如果你的程序涉及球从墙壁和彼此反弹,DCL可能会很有意义。它确实有效。即使没有争用,同步也必须比非同步慢一点,那么为什么如果一个简单的if可以阻止它呢?如果在所需对象已经存在的情况下,100个线程在同步语句中堆积,则必须慢得多。

答案 3 :(得分:0)

关键字“ synchronized”会生成内存屏障已满的栅栏,并不表示DCL可以正常工作。让我们以以下代码为例:

public static Runnable getInstance()
    {
        if (null == instance)    //1
        {
            synchronized (Runnable.class)
            {
                if (null == instance)
                {
                    instance = new Runnable(); //2
                }
            }
        }

        return instance;
    }

我们知道JVM在构造对象时将遵循许多步骤。我们在这里集中两个重要步骤: 首先,JVM为该对象分配内存。该对象中成员变量的值不明确。其次,JVM调用method并将其值分配给成员变量。

这意味着线程A可能在代码1中获得了部分构造的实例。尽管“同步”生成了内存屏障全围栏,但是代码1和代码2中没有happen-before保证。同步代码块。代码1在同步代码块之外。