最终领域与。易挥发的

Final fields Vs. Volatile

来自最终 field 语义的 java 文档:

Final field in JDK14

他们保证看到 final 字段如 constructor 中设置的那样,请找到下面的代码:

class FinalFieldExample { 
    final int x;
    int y; 
    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3; 
        y = 4; 
    } 

    static void writer() {
        f = new FinalFieldExample();
    } 

    static void reader() {
        if (f != null) {
            int i = f.x;  // guaranteed to see 3  
            int j = f.y;  // could see 0
        } 
    } 
}

现在我对 volatilefinal 感到困惑。

据我了解,final filed 用于确保您不能更改应用程序中的变量,volatile 保证保持顺序并避免发生关系之前发生。

所以我的问题是他们如何使用 final 变量而不是 volatile 来保证可见性和排序?请帮忙

So my question is how come they guarantee the visibility and ordering using final variable

因为他们是这样定义的,现在 VM 的工作就是遵守这个定义。

当然,后续的问题是:为什么要这样定义?

这是因为 Java 内存模型的一个奇怪的 "feature"。考虑这个例子

class Foo {
    int x;
    volatile int y;
    Foo() {
        x = 3;
        y = 4;
    }

    static final Foo INSTANCE;
    static {
       INSTANCE= new Foo();
    }
}

静态初始化程序将被编译成这个(简化的伪代码):

   Foo tmp = allocate(Foo.class)
   Foo.INSTANCE = tmp
   tmp.x = 3
   tmp.y = 4

如您所见,实例是在执行构造函数之前 public 创建的,volatile 这里没有任何改变。

对于大多数开发人员来说,这种行为是出乎意料的,并且可能导致非常难以调试的错误。因此,为了稍微减少这个问题的扩展,规范被调整为要求在创建实例之前初始化最终字段 public.

以上示例,x 声明为 final

   Foo tmp = allocate(Foo.class)
   tmp.x = 3
   Foo.INSTANCE = tmp
   tmp.y = 4