首页 > 解决方案 > 最终字段与。易挥发的

问题描述

从最终语义的java文档中:field

JDK14 中的 final 字段

他们保证看到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
        } 
    } 
}

现在在这里我对volatilevs感到困惑final

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

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

标签: javafinal

解决方案


所以我的问题是他们如何使用最终变量来保证可见性和排序

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

当然,接下来的问题是:他们为什么要这样定义?

这是因为 Java 内存模型的一个奇怪的“特性”。考虑这个例子

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

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

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

上面的示例,带有x声明final的 .

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

推荐阅读