java:为什么不允许它转义构造函数?
在JCIP的第3.2.1节“安全构造函数实践”中,有一个警告,警告不要将java:为什么不允许它转义构造函数?,java,concurrency,Java,Concurrency,在JCIP的第3.2.1节“安全构造函数实践”中,有一个警告,警告不要将此泄漏到构造函数的另一个线程,“即使发布是构造函数中的最后一条语句。”最后一部分对我来说似乎太强了,而且没有提供任何理由。施工后发生了什么事,我必须小心避免?有例外吗?我很感兴趣,因为我最近提交了一些代码,我在其中做了这件事,我想决定是否有理由回去进行重构。你不应该在任何时候从构造函数中泄露这个,“甚至在最后一条语句中[…]由于这个不是完全构建的,所以可能会发生一些非常奇怪的事情。请看一个非常类似的问题 您不应将此传递出构造
此
泄漏到构造函数的另一个线程,“即使发布是构造函数中的最后一条语句。”最后一部分对我来说似乎太强了,而且没有提供任何理由。施工后发生了什么事,我必须小心避免?有例外吗?我很感兴趣,因为我最近提交了一些代码,我在其中做了这件事,我想决定是否有理由回去进行重构。你不应该在任何时候从构造函数中泄露这个,“甚至在最后一条语句中[…]由于这个
不是完全构建的,所以可能会发生一些非常奇怪的事情。请看一个非常类似的问题 您不应将此
传递出构造函数(称为“泄漏此
”)
即使是构造函数的最后一行,也不应该这样做的一个原因是,只要对当前线程的影响不受影响,JVM就可以对语句重新排序。如果将此
传递给另一个线程中运行的进程,则重新排序可能会导致奇怪而微妙的错误
另一个原因是子类可能提供自己的初始化,因此在类的构造函数的最后一行构造可能不完整。就Java内存模型而言,构造函数出口在最终字段语义中起作用,因此,语句是在构造函数退出之前还是之后是有区别的
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();
(注意:shared
不是易变的;发布是通过数据竞争进行的。)
这两个示例之间的唯一区别是在构造函数退出之前或之后分配shared
。在第二个示例中,i=1
允许在赋值后重新排序
但是,如果发布是一个同步的操作,例如通过一个易失性变量,那么就可以了;其他线程将观察一个完全初始化的对象;这些字段甚至不必final
通过数据竞赛发布(或通过数据竞赛做任何事情)是一项非常棘手的业务,需要非常仔细的推理。如果您避免数据竞争,事情就会简单得多如果您的代码不包含数据竞争,那么在构造函数退出之前立即泄漏此
与在构造函数退出之后立即发布它之间没有区别。