我有一个班级项目
class Item {
public int count;
public Item(int count) {
this.count = count;
}
}
然后,我将在其他类
的字段中引用Itemclass Holder {
public Item item;
public Holder() {
item = new Item(50);
}
}
这个 new Item 对象可以安全发布吗?如果没有,为什么?根据Java Concurrency in Practice,新的Item发布而没有完全构造,但在我看来,新的Item是完全构造的:它的this
引用不会被转义并且引用它和它的状态是同时发布的,因此消费者线程不会看到陈旧的值。或者是可见性问题。我不知道原因。
答案 0 :(得分:14)
这个新的Item对象可以安全发布吗?如果没有,为什么?
问题围绕着指令的优化和重新排序。如果有两个线程使用构造对象而不进行同步,则可能会出现编译器决定为了效率而重新排序指令并为对象分配内存空间并将其引用存储在{{ 1}} 之前的字段它完成了构造函数和字段初始化。或者它可以重新排序内存同步,以便其他线程以这种方式感知。
如果将item
字段标记为item
,则保证构造函数完成该字段的初始化,作为构造函数的一部分。否则,在使用锁之前,您必须同步锁定。这是Java language definition。
这是另外几个参考文献:
答案 1 :(得分:5)
是的,存在可见性问题,因为Holder.item
不是final
。因此,无法保证在Holder
构造完成后,另一个线程将看到其初始值。
正如@Gray指出的那样,JVM可以在没有内存障碍的情况下重新排序指令(可以通过锁定(同步),final
或volatile
限定符来创建)。根据具体情况,您必须在此处使用其中一个以确保安全发布。