Java 最终字段Vs.Volatile

Java 最终字段Vs.Volatile,java,final,Java,Final,从final字段的java文档中语义: 他们保证看到构造函数中设置的最终字段,请查找以下代码: class FinalFieldExample { final int x; int y; static FinalFieldExample f; public FinalFieldExample() { x = 3; y = 4; } static void writer() { f =

从final
字段的
java
文档中
语义:

他们保证看到
构造函数中设置的
最终
字段,请查找以下代码:

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
        } 
    } 
}
现在我对
volatile
final
感到困惑

据我所知,使用的是
final
字段,确保您不能更改应用程序中的变量,并且
volatile
保证维护顺序,避免发生关系

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

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

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

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

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

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

    static final Foo INSTANCE;
    static {
       INSTANCE= new Foo();
    }
}
静态初始化器将编译成以下代码(简化伪代码):

如您所见,在执行构造函数之前,实例是公开的,
volatile
在这里不会改变任何东西

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

上面的示例,声明了
x
final

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

volatile
主要是关于可见性的。我不明白你的问题。。您能重新措辞吗?完成,请现在检查。
final
不保证订购。它确实保证了可见性,因为当一个字段是
final
时,它将不再被更改。如果一个线程缓存了该值,则该值对所有线程都保持不变。在可见性方面:每个线程都看到相同的东西。那么这是否意味着最终变量将不属于CPU缓存的一部分,而是直接写入内存中?从而确保不同CPU内核的所有线程始终看到最新的值。否,
final
与缓存本身无关。它保证了可见性,因为当字段初始化时,它将不再更改。这就是
final
的意思。最初使用该字段的每个线程都不会看到不同的值。在逻辑上,它总是一样的。线程可以在CPU寄存器或本地缓存中缓存该值,这不会对程序产生负面影响,因为该值总是相同的。不需要同步。值的可见性始终是有保证的。您是如何得出这个结论的?静态初始化程序将被编译成这个吗?@Savior,请参阅“显示它不工作的测试用例”,这是一篇非常过时的文章。在任何情况下,如果您问题中的示例反映了OP中的示例,我可能会同意。但您是在执行自身同步的
静态
块中进行实例化的。在初始化完成之前,没有其他线程可以看到
实例。如果你知道更多,请分享。我不应该说过时。我只是指过时的和非正式的。你能引用一些更正式的东西(比如JLS)并回答我之前的评论吗。对于您开始使用的示例代码,您关于事物顺序的声明是错误的。
   Foo tmp = allocate(Foo.class)
   tmp.x = 3
   Foo.INSTANCE = tmp
   tmp.y = 4