java:为什么不允许这个转义构造函数?

phi*_*ilo 6 java concurrency

在JCIP的第3.2.1节"安全构造函数实践"中,有一个警告,防止this从构造函数泄漏到另一个线程,"即使发布是构造函数中的最后一个语句." 最后一部分对我来说似乎太强大了,并没有任何理由.施工后发生了什么,我必须小心避免?有例外吗?我很感兴趣,因为我最近提交了一些代码,其中我做了这件事,我想决定是否有理由重新审视和重构.

irr*_*ble 4

就Java内存模型而言,构造函数退出在final字段语义中发挥作用,因此语句在构造函数退出之前或之后是有区别的。

This works                         This doesn't work
-------------------------------------------------------------

static Foo shared;                 static Foo shared;

class Foo                          class Foo
{                                  {   
    final int i;                       final int i; 
    Foo()                              Foo() 
    {                                  {
        i = 1;                             i = 1;
                                           shared = this;  
    }                                  }
}                                  }

shared = new Foo();                new Foo();
Run Code Online (Sandbox Code Playgroud)

(注意:shared不是易失性的;发布是通过数据竞争进行的。)

这两个示例之间的唯一区别是shared在构造函数退出之前或之后进行赋值。在第二个示例中,i=1允许在分配后重新排序。

但是,如果发布是同步操作,例如通过易失性变量,那么就可以了;其他线程将观察一个完全初始化的对象;字段甚至不需要final。

通过数据竞争进行发布(或通过数据竞争进行任何操作)是一项非常棘手的业务,需要非常仔细的推理。如果避免数据竞争,事情就会简单得多。如果您的代码不包含数据竞争,则在构造函数退出之前立即泄漏和在构造函数退出之后立即发布它没有区别。this