好吧,考虑Immutable下面给出的不可变类:
Immutable
public final class Immutable { final int x; final int y; public Immutable(int x,int y) { this.x = x; this.y = y; } //Setters public int getX() { return this.x; } public int getY() { return this.y; } }
现在,我正在Immutable一个类中创建一个对象,Sharable该对象的对象将由多个线程共享:
Sharable
public class Sharable { private static Immutable obj; public static Immutable getImmutableObject() { if (obj == null) --->(1) { synchronized(this) { if(obj == null) { obj = new Immutable(20,30); ---> (2) } } } return obj; ---> (3) } }
Thread A看到objas null并移入同步块并创建对象。现在,由于 Java内存模型(JMM)允许多个线程在初始化开始之后但尚未结束之前观察对象。 因此,Thread B可以将写入操作obj视为在写入的字段之前发生Immutable。因此,因此Thread B可以看到部分构造Immutable,该构造很可能处于无效状态,并且其状态以后可能会意外更改。
Thread A
obj
null
Thread B
它不是Immutable非线程安全的吗?
编辑 好,在仔细研究了SO并进行了一些评论之后,我知道 您可以 在构造对象之后 安全地在线程之间共享对不可变对象的引用 。另外,如@Makoto所述, 通常需要声明包含其引用的字段为volatile,以确保可见性 。另外,如@PeterLawrey所述,将对不可变对象的引用声明为,final使字段为thread-safe
final
thread-safe
因此,线程B可以看到对objas的写入发生在对Immutable字段的写入之前。因此,线程B可能因此看到部分构造的不可变,该不可变很可能处于无效状态,并且其状态以后可能会意外更改。
在Java 1.4中,这是正确的。在Java 5.0及更高版本中,构造后的final字段是线程安全的。