Java 如何在对象上将字段设为final以避免线程在同一对象上看到空引用?
Java并发的一个抽象/片段-Java 如何在对象上将字段设为final以避免线程在同一对象上看到空引用?,java,multithreading,concurrency,java.util.concurrent,Java,Multithreading,Concurrency,Java.util.concurrent,Java并发的一个抽象/片段- // Unsafe publication public Holder holder; public void initialize(){ holder = new holder(42); } 不正确发布的对象可能会出现两个问题。其他 线程可以看到holder字段的过时值,因此可以看到 null引用值或其他旧值,即使值已被删除 放在支架上。但更糟糕的是,其他线程可以看到一个到目前为止 holder引用的值,但状态的过期值 支架。为了使事情更不可预测,线
// Unsafe publication
public Holder holder;
public void initialize(){
holder = new holder(42);
}
不正确发布的对象可能会出现两个问题。其他
线程可以看到holder字段的过时值,因此可以看到
null引用值或其他旧值,即使值已被删除
放在支架上。但更糟糕的是,其他线程可以看到一个到目前为止
holder引用的值,但状态的过期值
支架。为了使事情更不可预测,线程可能会看到
第一次读取字段,然后读取更为最新的
下一次值,即为什么assertSanity可以抛出
断言错误
另外,对象引用对另一个线程可见并不一定意味着该对象的状态对消费线程可见
当然,解决这个问题的方法之一是做/做
public volatile Holder holder;
作者提出了一种不同的方法-
若Holder是不可变的,则assertSanity不能抛出
断言错误,即使持有者未正确发布。)
但是怎么做呢?不安全的出版物仍然存在。我认为线程仍然可以在holder上获得null引用。请建议。jls描述了final字段的特殊语义 最后一个字段还允许程序员实现线程安全的不可变对象,而无需同步。线程安全的不可变对象被所有线程视为不可变的,即使使用数据竞争在线程之间传递对不可变对象的引用。[...]. 必须正确使用final字段以保证不变性 但是我建议你读一下第17.5章 “必须正确使用”是指构造函数实际上已经结束(并且没有逃过
这个),并且没有篡改反射
翻译过来就是:
构造函数的结尾导致部分刷新,将所有最终变量和依赖对象写入内存。[...]. 对最终变量的第一次读取访问会导致部分刷新,从而加载最终变量并依赖内存中的对象。另一个引用未出现[…]
相关和
public volatile Holder holder;
public class Holder{
private final int n;
//...
}