Double check中的易失物质是什么?

时间:2011-03-26 19:07:56

标签: java algorithm concurrency synchronization

让我们看看经典的双重检查

class Foo {
    private volatile Foo singleton = null;
    public Foo getFooSingleton() {
        if (singleton == null) {
            synchronized(this) {           
                if (singleton == null)
                    singleton = new Foo();
            }
        }
        return singleton;
    }
}

易失性modifire保证在所有线程中都能正确看到“singleton”变量的值。但在当前的例子中我真的需要这个吗? 我想不是。所以 - 这就是我看到这个程序以最坏的方式运行的方式 - 当一个线程所做的更改被其他人看不到时。

  1. 线程一进入同步部分并创建单例
  2. 线程2 enteres synchronized,同步其当前堆栈值(现在他看到singleton != null),进行第二次检查并退出同步部分。
  3. 因此。即使没有挥发性声明,一切都有效,甚至更好=)

2 个答案:

答案 0 :(得分:5)

是的,此处需要volatile

关键是在创建Foo(包括创建对象和执行其构造函数)之间没有memory barrier并在singleton字段中存储对它的引用其他线程可以观察这些以任意顺序发生的动作。特别地,在第一次检查期间,线程2可以观察指向部分构造的对象的参考。请注意,synchronized阻止此处无法提供帮助,因为主题2会看到singleton != null并且根本不会输入它。

使用volatile确保放置适当的内存屏障(因为Java 5;在以前的版本中,根本无法实现双重检查习惯用法)。

答案 1 :(得分:2)

Java中的DCL问题不是额外同步的代价。真正的问题是没有volatile修饰符(在Java 5之前)你的线程可以看到构造不正确的singleton对象。

要清楚。写入singleton引用并写入singleton在单线程程序中顺序执行的字段可能在多线程中无序。