【发布时间】:2015-08-07 10:22:36
【问题描述】:
这是《Java Concurrency in Practice》一书的节选:
// Unsafe publication
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
...由于可见性问题,持有人可能会出现在其他人面前 线程处于不一致的状态,即使它的不变量是 由其构造函数正确建立!这种不正当的发布 可以允许另一个线程观察部分构造的对象。 ...
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.");
}
}
... 但更糟糕的是,其他线程可能会看到 持有人参考,但持有人状态的陈旧值。 ...
为了让事情变得更难预测,线程可能会看到一个陈旧的值 它第一次读取一个字段,然后读取一个更新的值 下一次,这就是为什么 assertSanity 可以抛出 AssertionError。 ... 这 对象构造函数首先将默认值写入所有字段 在子类构造函数运行之前。因此可以看到 字段的默认值作为陈旧值。
我的问题:
似乎只有两种情况 assertSanity() 可以抛出 AssertionError - 当“Holder”实例处于实例化过程中并且“n”的默认值尚未设置为“42”时。
Java 将在构造函数退出之前(在构造函数初始化“n”字段之前)将部分创建的对象放入“持有人”引用中。 另一个线程将尝试在这个部分创建的对象上调用“assertSanity”。 因此,“n != n”操作必须足够长,才能发生 AssertionError。
当本地缓存的“持有人”在 assertSanity() 正在进行时突然变得可见时。
还有其他情况吗?
谢谢大家!
【问题讨论】:
标签: java multithreading concurrency thread-safety