美文网首页
java对象的不正确的发布

java对象的不正确的发布

作者: 吃番茄的土拨鼠 | 来源:发表于2018-05-11 16:35 被阅读0次

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

由于上面的代码,对象未被正确发布,因此这个类可能出现故障,在调用assertSanity()方法时将抛出AssertionError异常[1],代码如下:

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对象对其他线程可见,因此将Holder称为“未被正确发布”。在未被正确发布的对象中存在两个问题。首先,除了发布对象的线程外,其他线程可能看到的Holder域是一个失效值,因此将看到一个空引用或者之前的旧值。然而,更糟糕的情况是,线程看到Holder引用的值是最新的,但Holder状态的值却是失效的[2]。情况变得更加不可预测的是,某个线程在第一次读取域时得到失效值,而再次读取这个域时会的到一个更新值。

如果没有足够的同步,那么当在多个线程间共享数据时将发生一些非常奇怪的事情。

[1] 问题并不在于Holder类本身,而是在于Holder类未被正确地发布。然而,如果将n声明为final类型,那么Holder将不可变,从而避免出现不正确发布的问题。

[2] 尽管在构造函数中设置的域值似乎是第一次向这些域中写入的值,因此不会有“更旧的”值被视为失效值,但Object的构造函数会在子类构造函数运行之前先将默认值写入所有的域。因此,某个域的默认值可能被视为失效值。

安全发布的常用模式

可变对象必须通过安全的方式来发布,这通常意味着在发布和使用该对象的线程时都必须使用同步。要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式来安全地发布:

在静态初始化函数中初始化一个对象引用;

将对象的引用保存到volatile类型的域或者AtomicReference对象中;

将对象的引用保存到某个正确构造对象的final类型域中;

将对象的引用保存到一个由锁保护的域中;

相关文章

网友评论

      本文标题:java对象的不正确的发布

      本文链接:https://www.haomeiwen.com/subject/cfafdftx.html