懒惰初始化SIngleton期间的数据竞争和竞争条件

时间:2014-02-17 13:06:43

标签: java multithreading

在阅读Brian Goetz撰写的 Java Concurrency in Practice 一书时,我遇到了数据竞赛和竞争条件。

数据竞赛

  

据说一个程序有一个数据竞争,因此不是一个   "正确同步"程序,当有一个读取的变量时   由多个线程编写,由至少一个线程编写,以及写入   并且读取不是由先前发生的关系排序的。

竞争条件

  

当计算的正确性取决于竞争条件时   关于多线程的相对时间或交错   运行;换句话说,当得到正确的答案依赖   幸运的时机。最常见的竞争条件是   check-then-act,用于制作可能过时的观察   关于下一步该做什么的决定

据我了解,可以通过确保上述一个或多个条件保持错误来避免数据竞争 - 即,通过使共享变量不可变或通过正确访问它们synchronized

我的问题是关于SingletonFactory的示例,通常用于说明竞争条件

e.g:

public class SingletonFactory {

    private Singleton singleton = null;

    private SingletonFactory() {}

    public Singleton getInstance() {
        if(this.singleton == null) {
            this.singleton = new Singleton();
        }
        return this.singleton;
   }
}

此代码是否也可以被视为导致数据竞争

我理解,使上述程序"完全线程安全" 的一种方法是拥有double checked locking并使类变量{{1} }。

但是,如果我只声明volatile变量Singleton,但无法同步初始化变量的代码块,那么它至少可以被认为是安全的"数据比赛",但仍然不安全竞争条件?总的来说,我仍然在寻找一个没有数据竞争的好的现实例子,但仍然存在潜在的竞争条件!

(通常被称为blog解释数据竞争和竞争条件之间的区别并不能帮助我理解这一点)

2 个答案:

答案 0 :(得分:4)

懒惰的单身人士通常会看到三种常见的风味。第一个是没有同步的,就像你的第一个例子。第二个,正如你所提到的那样是双重检查锁定没有volatile,最后是具有volatile的DCL。一个包含竞争条件(如果共享字段已同步),一个包含数据竞争。

public static class Singleton{
   private static volatile Singleton INSTANCE; // volatile to illustrate the race condition

   public static Singleton getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Singleton();
        }
        return INSTANCE;
   }
}

在这种情况下,不会发生数据竞争,但存在竞争条件。这里的竞争是两个或多个线程可以创建一个Singleton实例。

现在进行Double Checked锁定示例:

public static class Singleton{
   private static Singleton INSTANCE; // not volatile to illustrate the data-race

   public static Singleton getInstance(){
        if(INSTANCE == null){
            synchronized(Singleton.class){
                 INSTANCE = new Singleton();
            }
        }
        return INSTANCE;
   }
}

在这种情况下,是数据竞争,但不是竞争条件。尽管INSTANCE不为空,但INSTANCE变量发生的写入可能对其他线程不可见。

所以回答你的问题。

  

我的问题是这个代码是否也可以被认为是导致a   数据竞争?

在您的示例中,它包含数据争用和竞争条件,因为共享的可变变量既未同步也未同步check-then-set的原子操作。

答案 1 :(得分:0)

嗯,不,它不会是数据安全的,因为两个调用者仍然可以为“单例”找到两个不同的实例。

数据竞赛是一种竞争条件,但并非所有种族条件都是数据竞争。

也可能发生两条并行执行路径争夺结果。考虑信号 - 将SIGHUP SIGTERM发送到同一个进程。会发生什么?按什么顺序?即使执行之间没有明确的共享数据,行为也(通常)是非确定性的。