发布对象和线程安全

Bog*_* T. 6 java thread-safety

我在"Java Concurrency In Practice"中读到"在完全构造之前发布对象会损害线程安全性".有人可以解释一下吗?

M P*_*oet 2

new 运算符可以在类的构造函数完成之前返回一个值。因此,变量可能不会读取 null,但包含未初始化的类实例。这是由于字节重新排序而发生的。

一些澄清:从单线程的角度来看,JVM 允许对某些指令重新排序。传统上创建实例时,您可能会认为它是这样的:

  • 分配内存
  • 运行初始化(构造函数)
  • 将引用分配给 var

事实上,JVM 可能会执行以下操作:

  • 分配内存
  • 将引用分配给 var
  • 运行初始化(构造函数)

这具有性能优势,因为不需要再次查找地址。从单线程的角度来看,这不会改变逻辑的顺序。你的程序运行得很好。但这在多线程代码中带来了问题。这意味着可以在构造函数运行之前发布引用。因此,您需要一个“happens-before”规则来确保实例已完全初始化。将变量声明为 volatile dos 会强制执行此类发生在规则之前的规则。

有关重新排序的更多信息: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#reordering

  • 我本以为,引用可能不是在谈论在构造函数(或它调用的东西)中发布对象,而不是这个。我无法想象 new 运算符在调用的构造函数完成之前返回对象引用的情况。 (2认同)