下面的示例来自 Brian Goetz 的《Java Concurrency in Practice》一书,第 3 章,第 3.5.1 节。这是对象发布不当的示例:
class SomeClass {
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");
}
}
它表示 Holder 可能会以不一致的状态出现在另一个线程中,并且另一个线程可以观察到部分构造的对象。这怎么可能发生?你能用上面的例子给出一个场景吗?
它还继续说,在某些情况下,线程第一次读取字段时可能会看到一个陈旧的值,然后下次读取一个更新的值,这就是assertSanity
can throw的原因AssertionError
。怎么能AssertionError
扔?
通过进一步阅读,解决此问题的一种方法是Holder
通过将变量设为n
final 来使其不可变。现在,让我们假设它Holder
不是不可变的,但实际上是不可变的。
为了安全地发布这个对象,我们是否必须使持有者初始化为静态并将其声明为 volatile(静态初始化和 volatile 或只是 volatile)?
像这样的东西:
public class SomeClass {
public static volatile Holder holder = new Holder(42);
}