2013-02-09 44 views
8

从书Java并发的安全出版物中的做法:最终VS挥发性guaranntee w.rt对象

要安全地发布对象,无论是 参考对象和 对象的状态必须进行其他线程同时可见到 。甲 正确构造的对象可以是 安全地发布:

  • 初始化从静态初始化

  • 存储对它的引用到易失性字段或的AtomicReference

  • 存储一个对象引用参考它到一个正确构建的最终字段 对象

  • St或者将其引用到由锁定适当保护的字段中。

我的问题是:

  1. 有什么要点2和3之间的区别?我对volatile方法和final方法之间的差异感兴趣。
  2. 他指的是第3点的正确构造对象的最终字段是什么意思?在开始使用bulleted points之前,作者已经提到他们正在讨论一个正确构造的对象(我认为它不会让this引用转义)。但是为什么他们又提到了构造正确的物体呢?

回答

7

第2点和第3点的区别是什么?

  • volatile基本上意味着该领域的任何写操作会从其他线程可见。所以当你声明一个字段为volatile时:private volatile SomeType field;,你可以保证,如果构造函数写入该字段:field = new SomeType();,这个赋值将被随后尝试读取field的其他线程看到。
  • final具有相当类似的语义:如果您有最后一个字段:private final SomeType field;,则该字段的写入(无论是在声明中还是在构造函数中):field = new SomeType();都不会被重新编码,并且可以被其他人看到线程如果对象正确发布(即例如没有逃脱this)。

显然,主要的不同是如果该字段是最终的,您只能分配一次。

他指的是第3点中正确构造的物体的最终场是什么意思?

如果,例如,你让从构造this逃逸,由最终的语义提供的担保消失:一个观察线程可能会看到字段的默认值(空的对象)。如果对象构造得当,这不会发生。


人为的例子:

class SomeClass{ 
    private final SomeType field; 

    SomeClass() { 
     new Thread(new Runnable() { 
      public void run() { 
       SomeType copy = field; //copy could be null 
       copy.doSomething(); //could throw NullPointerException 
      } 
     }).start(); 
     field = new SomeType(); 
    } 
} 
+0

如果在构造完成后,我改变了像field.setX(new X())这样的字段引用的对象的状态,当我们声明它为volatile时,这个变化是否也保证被其他线程看到?还是它只是给初始化安全?最后在这种情况下呢? – Geek 2013-02-10 04:36:33

+0

不,只有'field'为您提供(重新)分配的可视性保证。除非'x'也是不稳定的,'field.x = new X();'(或者你的setter例子)不提供这样的保证。 – assylias 2013-02-10 07:48:15

+0

同样适用于final,推论如果'field'的所有成员都是final也是不可变的,则field不可变,因此它是线程安全的。 – assylias 2013-02-10 07:49:58

1

有什么出版volatile VS final,除了final的效果只能在构造函数中设置一次没有区别,这样的话你看什么不应该更改。

我相信正确构造对象确实你是指,一个对象,其this参考也没有逃脱它的构造,并已出版以安全的方式给线程,它是在使用什么。