我看到了这个陈述:
在正确构造的对象中,所有线程将看到最终字段的正确值,无论对象如何发布。
那么为什么需要使用volatile变量来安全地发布一个Immutable对象?
我真的很困惑。有人能用一个合适的例子来解释一下吗?
在正确构造的对象中,所有线程将看到最终字段的正确值,无论对象如何发布。
那么为什么需要使用volatile变量来安全地发布一个Immutable对象?
我真的很困惑。有人能用一个合适的例子来解释一下吗?
volatile变量的原因是它在对象构造和变量赋值之间建立了一个happens-before关系(根据Java内存模型)。这可以实现两个目标:
由于不可变对象的基本规则之一是在构造函数期间不发布引用,因此可能正在引用第二点。在没有适当并发处理的多线程环境中,有可能在构建对象之前“发布”对象的引用。因此,另一个线程可以获取该对象,看到其字段之一为null,然后稍后看到这个“不可变”对象已更改。
请注意,如果您具有其他适当的同步原语,则无需使用volatile字段来实现此目的-例如,如果赋值(以及所有后续读取)在给定监视器上的同步块中完成-但在“独立”意义上,将变量标记为 volatile
是告诉JVM“这可能被多个线程读取,请在该上下文中使分配安全”的最简单方法。
在Immutable类中,你无法真正看到差异。请看下面的例子,在Myclass.class
中。
public static Foo getInstance(){
if(INSTANCE == null){
INSTANCE = new Foo();
}
return INSTANCE;
}
final Foo INSTANCE;
),它将确保不会在构造函数调用期间发布引用。部分对象构建是不可能的。Myclass
是不可变的,那么在对象构造之后它的状态就不会改变,使得Volatile关键字(volatile final Foo INSTANCE;
)变得多余。但是如果这个类允许其对象状态被更改(非不可变),则多个线程可以实际上更新对象,并且一些更新对其他线程不可见,因此volatile关键字确保了非不可变类中对象的安全发布。