如果将对象分配给最终字段,其他线程是否会看到该对象的非最终/非易失性字段的先前更新?

7 java concurrency multithreading volatile thread-safety

阅读Java语言规范,我发现了关于最终字段的摘录:

最终字段的使用模型很简单:在该对象的构造函数中设置对象的最终字段; 并且在对象的构造函数完成之前,不要在另一个线程可以看到的地方写入对正在构造的对象的引用.如果遵循此原因,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本.它还将看到那些最终字段引用的任何对象或数组的版本,这些字段至少与最终字段一样是最新的.

链接:https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5

我的问题是,"版本"是否意味着更新?这意味着最终字段引用的对象的非final/non-volatile字段也将在构造后从主内存(而不是本地缓存)中读取?


因此,假设thread #1创建一个objectB并设置其非最终/非易失性字段之一.

然后thread #2将相同的字段设置为不同的字段,创建其他objectA字段设置为最终字段objectB,然后将其objectA放在thread #1可以获取它的位置.

thread #1然后得到objectA,并看到它的最后一个领域objectB.是否有可能thread #1看不到objectB所做的更改thread #2

或者这里有一些显示我的意思的代码:

public class Test {
    private static final ConcurrentLinkedQueue<A> myAs = new ConcurrentLinkedQueue<>();
    private static long timer = System.nanoTime() + 3000000000L; // 3 seconds into the future

    public static void main(String... args) {
        B myB = new B("thread #1"); // Set in thread 1

        new Thread(() -> {
            myB.setString("thread #2"); // Set in thread 2
            myAs.add(new A(myB));
        }).start();

        for(long i = 0; i < x; i = System.nanoTime()) {} // Busy-wait for about 3 seconds

        System.out.println(myAs.poll().getB().getString()); // Print out value
    }

    public static class A {
        private final B b;

        public A(B b) {
            this.b = b;
        }

        public B getB() {
            return b;
        }
    }

    public static class B {
        private String s = null;

        public B(String s) {
            this.s = s;
        }

        public String getString() {
            return s;
        }

        public void setString(String s) {
            this.s = s;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

代码似乎读取了更新的值,但我不确定这是否仅仅是出于随机运气.

小智 0

恕我直言,你总是会看到更新的值。这里发生了两件事

  1. 安全出版
  2. 冻结构造函数末尾的操作

由于我们有冻结操作,其他线程应该能够看到 myB 的内容

更多详细信息: https://shipilev.net/blog/2014/jmm-pragmatics/#_part_v_finals

https://www.ibm.com/developerworks/library/j-jtp03304/index.html