Java 内存模型:创建最终实例字段的循环参考图是否安全,所有字段都在同一线程中分配?
比我更了解 Java 内存模型的人能否确认我对以下代码已正确同步的理解?
class Foo {
private final Bar bar;
Foo() {
this.bar = new Bar(this);
}
}
class Bar {
private final Foo foo;
Bar(Foo foo) {
this.foo = foo;
}
}
我知道这段代码是正确的,但我还没有完成整个发生 - 在数学之前。我确实发现了两个非正式的引文,表明这是合法的,尽管我对完全依赖它们有点警惕:
最终字段的使用模型很简单:在对象的构造函数中设置对象的最终字段;并且不要在对象的构造函数完成之前,在另一个线程可以看到它的位置写入对正在构造的对象的引用。如果遵循此命令,则当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本。它还将看到由最终字段引用的任何对象或数组的版本,这些字段至少与最终字段一样最新。[Java® 语言规范:Java SE 7 版,第 17.5 节]
另一个参考:
正确构造对象意味着什么?它只是意味着在构造过程中不允许对正在构造的对象的引用“逃脱”。(有关示例,请参阅安全施工技术。换句话说,不要将对正在构造的对象的引用放在另一个线程可能能够看到它的任何位置;不要将其分配给静态字段,不要将其注册为任何其他对象的侦听器,依此类推。这些任务应在构造函数完成后完成,而不是在构造函数中完成。[JSR 133(Java 内存模型)常见问题解答,“最终字段如何在新的 JMM 下工作?]