不一致的状态比较 Java
Inconsistent State Comparison Java
在Java并发实践中给出了一个例子*来演示可见性问题,由于缺乏同步,两个不同的线程可能看不到任何特定可变对象的最新状态。
public class Holder {
private int n;
public Holder(int n) { this.n = n; }
public void assertSanity() {
if (n != n){
throw new AssertionError("This statement is false.");
}
}
在这个特定的示例中,书中指出 Thread "A" 应该首先通过 Thread 不安全的方式初始化并发布它,例如:
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
然后线程 "B" 调用 holder.assertSanity()
,由于状态不一致,完全有可能抛出 AssertionError
。
现在,我理解了该论点的基本前提,即对可变变量所做的更改可能永远不会被另一个线程观察到。但我在这里感到困惑的是,它正在比较相同的(或者我认为)参考 n != n
。
这不是比较可变原始字段的值private int n
吗?不管 n
现在对线程 A 的值可能是 42,对线程 B 的值是 0(默认值),不应该直接调用来检查它在 same[ 中的值=39=]线程是一致的?即,在线程 A 中调用 assertSanity()
将检查是否 42 != 42
,而在线程 B 中调用 0 != 0
?
*引用自 3.5 Safe Publication,书中的清单 3.14 和 3.15。
问题是在表达式 n != n
中变量 n
将被加载两次(假设没有优化字节码)。在这两个负载之间,另一个线程可以更改该值。
在线程 B n != n
比较期间,B 检索 n
两次。同时,在线程 A 中运行的构造函数会将 n 的值从默认值 0 修改为 42。
在Java并发实践中给出了一个例子*来演示可见性问题,由于缺乏同步,两个不同的线程可能看不到任何特定可变对象的最新状态。
public class Holder {
private int n;
public Holder(int n) { this.n = n; }
public void assertSanity() {
if (n != n){
throw new AssertionError("This statement is false.");
}
}
在这个特定的示例中,书中指出 Thread "A" 应该首先通过 Thread 不安全的方式初始化并发布它,例如:
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
然后线程 "B" 调用 holder.assertSanity()
,由于状态不一致,完全有可能抛出 AssertionError
。
现在,我理解了该论点的基本前提,即对可变变量所做的更改可能永远不会被另一个线程观察到。但我在这里感到困惑的是,它正在比较相同的(或者我认为)参考 n != n
。
这不是比较可变原始字段的值private int n
吗?不管 n
现在对线程 A 的值可能是 42,对线程 B 的值是 0(默认值),不应该直接调用来检查它在 same[ 中的值=39=]线程是一致的?即,在线程 A 中调用 assertSanity()
将检查是否 42 != 42
,而在线程 B 中调用 0 != 0
?
*引用自 3.5 Safe Publication,书中的清单 3.14 和 3.15。
问题是在表达式 n != n
中变量 n
将被加载两次(假设没有优化字节码)。在这两个负载之间,另一个线程可以更改该值。
在线程 B n != n
比较期间,B 检索 n
两次。同时,在线程 A 中运行的构造函数会将 n 的值从默认值 0 修改为 42。