在阅读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解释数据竞争和竞争条件之间的区别并不能帮助我理解这一点)
答案 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发送到同一个进程。会发生什么?按什么顺序?即使执行之间没有明确的共享数据,行为也(通常)是非确定性的。