我想确保根据Java内存模型正确理解“有效不可变对象”的行为。
假设我们有一个可变的类,我们希望将其发布为有效的不可变的类:
class Outworld { // This MAY be accessed by multiple threads public static volatile MutableLong published; } // This class is mutable class MutableLong { private long value; public MutableLong(long value) { this.value = value; } public void increment() { value++; } public long get() { return value; } }
我们执行以下操作:
// Create a mutable object and modify it MutableLong val = new MutableLong(1); val.increment(); val.increment(); // No more modifications // UPDATED: Let's say for this example we are completely sure // that no one will ever call increment() since now // Publish it safely and consider Effectively Immutable Outworld.published = val;
问题是 :Java内存模型是否保证所有线程都必须具有Outworld.published.get() == 3?
Outworld.published.get() == 3
根据 Java Concurrency In Practice, 这应该是正确的,但是如果我错了,请更正我。
3.5.3。安全出版惯用语 为了安全地发布对象,必须同时使对该对象的引用和该对象的状态对其他线程可见。可以通过以下方式安全地发布正确构造的对象: -从静态初始化程序初始化对象引用; -将对它的引用存储到volatile字段或AtomicReference中; -将对它的引用存储到正确构造的对象的最终字段中;或 -将对其的引用存储到由锁适当保护的字段中。 3.5.4。有效的不可变对象 安全发布的有效不变对象可以被任何线程安全使用,而无需额外的同步。
3.5.3。安全出版惯用语
为了安全地发布对象,必须同时使对该对象的引用和该对象的状态对其他线程可见。可以通过以下方式安全地发布正确构造的对象: -从静态初始化程序初始化对象引用; -将对它的引用存储到volatile字段或AtomicReference中; -将对它的引用存储到正确构造的对象的最终字段中;或 -将对其的引用存储到由锁适当保护的字段中。
3.5.4。有效的不可变对象
安全发布的有效不变对象可以被任何线程安全使用,而无需额外的同步。
是。在读取之前,对的写入操作MutableLong后跟一个happens-before关系(在volatile上)。
MutableLong
happens-before
(有可能一个线程Outworld.published不安全地读取并将其传递给另一个线程。从理论上讲,它可以看到更早的状态。实际上,我看不到它的发生。)
Outworld.published