全部:
这是著名的文章:
它声明该模式在 Java 中不起作用。它进一步说,接近尾声,新的 JVM 可以通过使用 volatile 使该模式工作。
但是,在另一篇文章中:Memory Barriers and JVM Concurrency
它说关键字“同步”会生成内存屏障完整围栏。那么谁是对的呢?该模式在地球上的 Java 中是否有效?
全部:
这是著名的文章:
它声明该模式在 Java 中不起作用。它进一步说,接近尾声,新的 JVM 可以通过使用 volatile 使该模式工作。
但是,在另一篇文章中:Memory Barriers and JVM Concurrency
它说关键字“同步”会生成内存屏障完整围栏。那么谁是对的呢?该模式在地球上的 Java 中是否有效?
基本上有 3 种方法可以修复双重检查锁定:
确保变量被声明为volatile(从 Java 5 开始工作);
只是一开始就不要理会它:只需使用同步,不要试图用花哨的容易出错的——而且可能毫无意义的——“避免”它的手段来搞乱;
让类加载器为你做同步。
我在这里发布了示例代码。
但是:双重检查锁定确实是一种过时的范例,如果它确实在 Java 中有用的话。正如我所看到的,它基本上是由 C 程序员转入 Java 的,他们没有完全意识到 JVM 有效地有一种更有效(和正确!)的方式来处理内置于类加载器中的问题,并且对同步的优化是通常最好在 JVM 级别制作。
我见过很多人用这种“模式”弄乱他们的代码。我认为我从未见过任何实际数据表明它有任何好处。
另外:如果您确实有一个遇到同步问题的大型应用程序,那么 Java 存在的全部理由之一就是它具有丰富的并发库。看看如何重新设计应用程序以使用它们……如果分析数据证明它是必要的。
这取决于您使用的 java 版本。这已在 java 5 及更高版本中修复。
检查http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
他们都是对的,并且 DCL 从 Java 5 开始就可以正常工作。
如果您希望您的程序在给定完全相同的输入的情况下每次都产生完全相同的输出,并且您正在使用 DCL,那么您可能需要认真重新考虑您在做什么。很多事情取决于谁先拿到锁——你掷了很多骰子。不适合会计应用程序。
如果您的程序涉及球在墙壁和彼此之间反弹,那么 DCL 可能很有意义。它确实有效。即使没有争用,同步也必须比非同步慢一点,那么如果一个简单的if
可以阻止它,为什么要这样做呢?如果在需要的对象已经存在时有 100 个线程堆积在一个同步语句上,那肯定会慢很多。
生成内存屏障全栅栏的关键字“同步”并不意味着 DCL 可以正常工作。我们以下面的代码为例:
public static Runnable getInstance()
{
if (null == instance) //1
{
synchronized (Runnable.class)
{
if (null == instance)
{
instance = new Runnable(); //2
}
}
}
return instance;
}
我们知道 JVM 在构造对象时会遵循很多步骤。我们在这里关注两个重要步骤:首先,JVM malloc 为这个对象分配内存。此对象中的成员变量的值现在具有默认值。其次,JVM调用方法并将用户指定的值分配给成员变量。
这意味着线程 A 可能会在代码 1 中(在代码 1 和代码 2 的中间)获得一个部分构造的实例。虽然“synchronized”会生成内存屏障全栅栏,但在代码 1 和代码 2 中没有发生之前的保证。内存屏障栅栏在同步代码块期间生效。代码 1 在同步代码块之外。