我正在阅读 Java Concurrency in Practice by Brian Goetz .在第 51 页。在其中一个脚注中,他说:
While it may seem that field values set in a constructor are the first values written to those fields and therefore that there are no “older” values to see as stale values, the Object constructor first writes the default values to all fields before subclass constructors run. It is therefore possible to see the default value for a field as a stale value.
所以,final 字段的概念现在对我来说还不是很清楚。考虑示例类:
public class MyClass{
private final MyImmutableClass mic;
public MyClass(){
mic = MyImmutableClass.empty();
}
}
根据上面的脚注,mic
字段被分配了两次,一次是由 Object
的构造函数和一次由 MyClass
的构造函数本身。现在,假设我们不安全地发布了一个 MyClass
对象(例如通过 public
字段):
public final MyClass mc;
谁保证 mc
总是被处于一致状态的任何线程观察到?为什么某些线程不能意外观察到默认值?
据我所知,final
字段本身只保证对象构造后不能分配引用。如果我们将 mc
声明为 volatile,那就很清楚了。任何读取该字段的线程都应该直接从内存中读取它。禁止从缓存中读取。
UPD:发布示例:
public static void main(String[] args){
class MyRunnable implements Runnable(){
private SomeClass sc;
public MyRunnable(SomeClass sc){
this.sc = sc;
}
public void run(){
//do some with sc
}
}
SomeClass sc = getInitialized();
ExecutorService es = Executors.newFixedThreadPool(10);
MyRunnable mr = new MyRunnable(sc);
//submiting mr to es 10 times
es.awaitTemination();
es.shutdown();
}
private static SomeClass getInitialized(){
SomeClass sc = new SomeClass();
sc. initialize();
return sc;
}
public class SomeClass
public MyClass mc;
public void initialize(){
mc = new MyClass();
}
}
SomeClass
实例将跨多个线程发布。某些线程是否可以观察到 mic
字段的默认值?
最佳答案
mc
在你的例子中是一个实例变量。这意味着您必须具有包含 mc
的类的完全初始化实例,以便访问某个实例的 mc
的任何代码都不会抛出 NullPointerException
。所以mc
肯定会在访问的时候被初始化。
关于java - 为什么发布最终字段是安全的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34489288/