不一致的状态比较Java

时间:2018-06-02 11:11:05

标签: java multithreading volatile mutable

Java Concurrency In Practice 中,给出了一个示例*来演示 visibility 的问题,其中两个不同的线程可能看不到由于缺乏同步,任何特定可变对象的最新状态。

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.");
        }
    }

在这个特定的例子中,该书指出,如果线程“A”首先初始化并通过线程不安全的方式发布它,例如:

public Holder holder;
public void initialize() {
    holder = new Holder(42);
}

然后线程“B”调用holder.assertSanity(),由于状态不一致,完全有可能抛出AssertionError

现在,我理解了论证的基本前提,即对另一个线程永远不会观察到对可变变量的更改。但我在这里感到困惑的是它正在比较相同(或者我认为)的参考n != n

这不是比较可变原始字段private int n的值吗?无论n现在对于线程A的值是42,对于线程B的值是0(默认值),也不应该直接调用它来检查相同线程一致?即在线程A中调用assertSanity()将检查42 != 42是否在线程B中0 != 0

*参考3.5安全出版物,清单3.14& 3.15在书中。

2 个答案:

答案 0 :(得分:1)

问题是在表达式n != n中,变量n将被加载两次(假设没有优化字节码)。在这两个负载之间,另一个线程可以改变该值。

答案 1 :(得分:1)

在线程B n != n中进行比较时,B检索n两次。同时,构造函数在线程A中运行会将n的值从默认值0修改为42。