最终字段Vs.易挥发

问题描述 投票:0回答:1

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

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字段用于确保您无法在应用程序中更改变量,并且volatile保证保持顺序并避免在发生关系之前发生。

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

java final
1个回答
1
投票

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

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

当然,后续问题是:为什么他们用这种方式定义它?

这是由于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
© www.soinside.com 2019 - 2024. All rights reserved.