Java内存模型和最终字段 [英] Java Memory Model and final fields

查看:100
本文介绍了Java内存模型和最终字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,当我向JMM提出与最终"相关的担保时,我感到困惑.这是JMM的摘录和示例

I recently got confused when i referred to JMM for guarantees associated with "final". Here is an excerpt and example from JMM

图4给出了一个示例,该示例演示了如何将最终字段与正常字段进行比较.班级 FinalFieldExample具有最终字段x和非最终字段y.一个线程可以执行方法writer(),而另一个线程可以执行方法reader().因为writer()写f 在对象的构造函数完成之后,将保证reader()可以看到f.x的正确初始化值:它将读取值3.因此,不能保证reader()方法的值是4

Figure 4 gives an example that demonstrates how final fields compare to normal fields. The class FinalFieldExample has a final int field x and a non-final int field y. One thread might execute the method writer(), and another might execute the method reader(). Because writer() writes f after the object’s constructor finishes, the reader() will be guaranteed to see the properly initialized value for f.x: it will read the value 3. However, f.y is not final; the reader() method is therefore not guaranteed to see the value 4 for it

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
      }
    }
}

我的困惑是,对象'Obj'的final和non-final字段是否已完全初始化并由线程'T'引用,T将仅看到final字段的正确值吗?构造后不会发生突变的非最终字段呢?我了解,如果在构造线程"T"之后对它们进行了突变,则可能看不到新值(除非该字段为volatile).但是,如果该字段是非最终且非易失性的,并且在构造之后没有发生突变,我该怎么办?

My confusion is that is an object 'Obj' has final and non-final fields is fully initialized and is being referenced by a Thread 'T', T will only see correct values for final fields ? What about non-final fields that are not mutated after construction. I understand that if they are mutated after construction thread 'T' might not see new value ( unless the field is a volatile ). But i am what if the field is non-final and non-volatile and is not mutated after construction ?

JVM如何实现与最终"关联的保证?例如,对于易失性,存在存储障碍.

How does JVM implements guarantees associated with 'final' ? E.g for volatile there are memory barriers.

推荐答案

此问题已解决:

这是对象的安全发布吗?

引用:

问题围绕指令的优化和重新排序.当您有两个正在使用构造对象且没有同步的线程时,出于效率考虑,编译器可能会决定对指令重新排序,并为对象分配内存空间,然后在构造函数和构造函数完成之前将其引用存储在item字段中.字段初始化.或者,它可以重新排序内存同步,以便其他线程以这种方式感知它.

The issue revolves around optimizations and reordering of instructions. When you have two threads that are using a constructed object without synchronization, it may happen that the compiler decides to reorder instructions for efficiency sake and allocate the memory space for an object and store its reference in the item field before it finishes with the constructor and the field initialization. Or it can reorder the memory synchronization so that other threads perceive it that way.

如果将一个字段标记为final,它将强制编译器在构造函数完成之前完成对该字段的初始化.非最终字段没有这样的保证.

If you mark a field as final it forces the compiler to complete initialization for that field before the constructor completes. Non-final fields have no such guarantees.

这是的一部分Java语言定义(17.4).关于final字段的详细信息也位于

This is part of the Java language definition (17.4). Details about final fields are also in the JLS (17.5).

更具体地说,writer()方法构造了FinalFieldExample的实例,并将其存储在static字段中,以供其他线程使用.由于指令重新排序,y字段可能尚未初始化.如果相同线程调用reader(),则它将y视为4,但其他线程却将其视为0,因为已设置f并可能使用了 before y初始化并发布.

More specifically, the writer() method constructs an instance of FinalFieldExample and stores in in a static field for other threads to consume. Because of instruction reordering, the y field may not have been initialized yet. If the same thread calls the reader() it will see y as 4 but other threads could see it as 0 because f was set and consumed possibly before y gets initialized and published.

要使此代码正确无误,还必须将f也设置为volatile.

To make this code correct, you must make f be volatile as well.

这篇关于Java内存模型和最终字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆