java - 为什么发布最终字段是安全的?

标签 java multithreading final

我正在阅读 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/

相关文章:

java - 使用 jQuery-ajax 和 Servlet 的阿拉伯语数据

java - 如何使 String 变量的值在分配后不改变?

initialization - Kotlin val 初始化使用 when

java - 从另一个可观察对象调用可观察对象

java - 在 Scanner.nextInt() 之后使用 Scanner.nextLine()

Java try catch block

multithreading - 是否准确地说每个响应输入的程序都有一个无限循环的主线程?

c++ - 当 future 离开范围时,线程会去哪里?

c++ - memcpy() 相邻内存区域的安全性

java - 为什么 String 类在 Java 中声明为 final?