有人可以阐明与完整初始化有关的Java内存模型最终字段语义吗?

时间:2018-08-30 23:09:52

标签: java multithreading

来自Java Memory Model specification

  

当对象的构造函数完成时,就认为该对象已完全初始化。保证只有在对象完全初始化之后才能看到对对象的引用的线程才能保证看到该对象的最终字段的正确初始化值。

让我感到困惑的部分是这句话:

  

一个线程只能在完全初始化该对象之后才能看到对该对象的引用,这可以确保看到该对象的最终字段的正确初始化值。

句子的主题是

  

仅在对象完全初始化后才能看到对对象的引用的线程

声明的其余部分仅适用于该主题。这向我暗示,在对象完全初始化之前,有一些线程可以看到对对象的引用。

如果存在此类线程,则本规范中与最终字段有关的保证仅在某些情况下适用。

Goetz在旧的Brian Goetz article from 2001中描述了一种情况:

  

假设线程B在分配内存和设置资源字段之后但在调用构造函数之前出现。它看到资源不为空,跳过同步块,并返回对部分构造的Resource的引用!

这表明实际上有线程可以在对象完全初始化之前看到对对象的引用。

然后,Goetz继续说明使用volatile还是不能解决该问题。

那么,如何保证在完全初始化对象A之前某些对象B看不到某些新的对象A?似乎只有在满足这些条件的情况下,使用final字段才有用。

1 个答案:

答案 0 :(得分:0)

  

这向我建议,在完全初始化对象之前,有些线程可以看到对该对象的引用。

是的。

如果构造函数或构造函数调用的某些方法将this发布到其他线程可以看到它的某个位置,则会发生这种情况。 Goetz et al将此称为“不安全出版物”(IIRC。我的这本书的副本位于约2公里的书架上。)

  

那么,如何保证对象B在对象A完全初始化之前看不到某些新的对象A?

ObjectA构造函数不应将this发布到其他线程可以看到的地方。那么一切都很好 1


1-....关于“ all”的某些定义。我们仍然必须解决世界和平问题。