If you assign an Object to a final field, will other threads see previous updates of that Object's non-final/non-volatile fields?

user8021515 :

Reading the Java language specs, I found this excerpt about final fields:

The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.

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

My question is, does "versions" mean updates? This means that the non-final/non-volatile fields of an object referenced by a final field will also be read from main memory (not the local cache) after construction?


Example

So let's say thread #1 creates an objectB and sets one of its non-final/non-volatile fields.

Then thread #2 sets that same field to something different, creates some other objectA with a final field set as objectB, then puts that objectA somewhere where thread #1 can get it.

thread #1 then gets the objectA, and sees its final field as objectB. Is it possible for thread #1 to not see the changes to objectB made by thread #2?

Or here is some code showing what I mean:

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

The code seems to read the updated values, but I'm not sure if that's just out of random luck.

Neerav Vadodaria :

IMHO you will always see the updated value.. There are 2 things which are happening here

  1. Safe publication
  2. Freeze action at the end of the constructor

As we have a freeze action other thread should be able to see the content of myB

More details : https://shipilev.net/blog/2014/jmm-pragmatics/#_part_v_finals

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

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=463003&siteId=1