所有
这是着名的文章:
The "Double-Checked Locking is Broken" Declaration
它声明模式在Java中不起作用。它接着说,新的JVM可以通过使用volatile来使模式工作。
但是,在另一篇文章中:Memory Barriers and JVM Concurrency
它表示关键字“synchronized”会生成内存屏障全屏障。那么谁是对的?该模式是否适用于地球上的Java?
答案 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在同步代码块之外。