为什么发布最终字段安全?

St.*_*rio 2 java multithreading final

我目前正在阅读Brian Goetz的Java Concurrency in Practice.在第51页.在其中一个脚注中,他说:

虽然它可能似乎在构造函数中设置字段的值写入这些字段中的第一个值,因此不存在"老"值看作为过时的值,子类的构造函数运行之前Object构造函数首先写入默认值到所有领域.因此,可以将字段的默认值视为陈旧值.

所以,最终领域的概念现在还不清楚.考虑样本类:

public class MyClass{
    private final MyImmutableClass mic;

    public MyClass(){
        mic = MyImmutableClass.empty();
    }
}
Run Code Online (Sandbox Code Playgroud)

根据上面的脚注,mic字段被分配两次,一次由Object构造函数指定,一次由构造MyClass函数本身指定.现在,假设我们MyClass不安全地发布了一个对象(例如通过public字段):

public final MyClass mc;
Run Code Online (Sandbox Code Playgroud)

谁保证mc一致状态下的任何线程都能始终观察到?为什么有些线程不会意外地观察到默认值?

据我所知,该final字段本身仅保证在对象构造之后不能分配引用.如果我们宣布mc挥发性,那将是明确的.读取该字段的任何线程都应该直接从内存中读取它.禁止从缓存中读取它.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

一个SomeClass实例将在多个线程中发布.某些线程可以观察到该mic字段的默认值吗?

Era*_*ran 5

mc在您的示例中是一个实例变量.这意味着您必须拥有一个完全初始化的类实例,mc以便访问mc某些实例的任何代码都不会抛出NullPointerException.因此,mc肯定会在访问时初始化.