这是对象的安全发布吗?

ohy*_*zai 7 java multithreading

我有一个课程项目

class Item {
  public int count;
  public Item(int count) {
    this.count = count;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,我将在其他类的字段中引用Item

class Holder {
  public Item item;
  public Holder() {
    item = new Item(50);
  }
}
Run Code Online (Sandbox Code Playgroud)

这个新的Item对象可以安全发布吗?如果没有,为什么?根据Java Concurrency in Practice,新的Item是在没有完全构造的情况下发布的,但在我看来,新的Item是完全构造的:它的this引用不会被转义,并且它的引用和它的状态同时发布,所以消费者线程不会看到过时的价值.或者是可见性问题.我不知道原因.

Gra*_*ray 15

这个新的Item对象可以安全发布吗?如果没有,为什么?

该问题围绕指令的优化和重新排序.当你有两个线程使用没有同步的构造对象时,可能会发生这样的情况:编译器决定为了效率而重新排序指令并为对象分配内存空间并它完成构造函数之前将其引用存储在item字段中字段初始化.或者它可以重新排序内存同步,以便其他线程以这种方式感知它.

如果您将该item字段标记为,final那么构造函数将保证完成该字段的初始化作为构造函数的一部分.否则,在使用锁之前,您必须同步锁定.这是Java语言定义的一部分.

这是另外几个参考:


Pét*_*rök 6

是的,存在可见性问题,但事实Holder.item并非如此final.因此,无法保证在构造Holder完成后,另一个线程将看到其初始化值.

和作为@Gray指出的那样,JVM可以自由地重新排序在没有存储器屏障指令(其可以由一个锁(同步地创建的),一个finalvolatile限定符).根据具体情况,您必须在此处使用其中一个以确保安全发布.