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

sen*_*iwu 6 java multithreading

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

数据竞赛

当有一个由多个线程读取的变量,由至少一个线程写入,并且写入和读取不是时,程序被称为具有数据竞争,因此不是"正确同步"的程序以前发生的关系命令.

比赛条件

当计算的正确性取决于运行时的多个线程的相对定时或交错时,就会出现竞争条件; 换句话说,当得到正确的答案依赖于幸运时间.最常见的竞争条件类型是check-then-act,其中使用可能陈旧的观察来决定下一步该做什么

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

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

例如:

public class SingletonFactory {

    private Singleton singleton = null;

    private SingletonFactory() {}

    public Singleton getInstance() {
        if(this.singleton == null) {
            this.singleton = new Singleton();
        }
        return this.singleton;
   }
}
Run Code Online (Sandbox Code Playgroud)

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

我知道使上述程序"完全线程安全"的一种方法是使用双重检查锁定并使类变量volatile.

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

(一个通常被称为解释数据竞争和竞争条件之间差异的博客并没有帮助我理解这一点)

Joh*_*int 5

懒惰的Singleton通常具有三种常见的风味。第一个是没有同步的,就像您的第一个示例一样。正如您提到的,第二个是不使用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;
   }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,不会碰到数据争用,但是会出现竞态条件。这里的竞争是两个或更多线程可以创建一个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;
   }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,存在数据争用,但没有竞争条件。尽管INSTANCE不为null,但其他线程可能看不到INSTANCE变量发生的写入。

因此,回答您的问题。

我的问题是,是否也可以将此代码引起数据争用?

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