3.5 安全发布

到目前为止,我们重点讨论的是如何确保对象不被发布,例如让对象封闭在线程或另一个对象的内部。当然,在某些情况下我们希望在多个线程间共享对象,此时必须确保安全地进行共享。然而,如果只是像程序清单3-14那样将对象引用保存到公有域中,那么还不足以安全地发布这个对象。

程序清单3-14 在没有足够同步的情况下发布对象(不要这么做)

//不安全的发布

public Holder holder;

public void initialize(){

holder=new Holder(42);

}

你可能会奇怪,这个看似没有问题的示例何以会运行失败。由于存在可见性问题,其他线程看到的Holder对象将处于不一致的状态,即便在该对象的构造函数中已经正确地构建了不变性条件。这种不正确的发布导致其他线程看到尚未创建完成的对象。

3.5.1 不正确的发布:正确的对象被破坏

你不能指望一个尚未被完全创建的对象拥有完整性。某个观察该对象的线程将看到对象处于不一致的状态,然后看到对象的状态突然发生变化,即使线程在对象发布后还没有修改过它。事实上,如果程序清单3-15中的Holder使用程序清单3-14中的不安全发布方式,那么另一个线程在调用assertSanity时将抛出AssertionError。[1]

程序清单3-15 由于未被正确发布,因此这个类可能出现故障

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

Get Java并发编程实战 now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.