简体   繁体   中英

Java Array Synchronization (Visibility)

I am trying to understand exactly how element visibility works on arrays in java.

Given the class:

class IntList {

    private final int[] array;

    public IntList(int[] array) {
        this.array = array;
    }

    public int[] readElements() {
        return Arrays.copyof(this.array, this.array.length);
    }

}    

and the following method body for creating an instance:

int[] array = new int[length];
fillArrayWithRandomData(array); // puts data into the array from arbitrary source
return new IntList(array);

I am wondering if the elements in the IntList are guaranteed to be visible by other threads that obtain a reference to the returned IntList ?

I am sure that the REFERENCE to the array will be visible because it is final but I cannot seem to find a guarantee that the elements in the array will be visible as well.

Note: The IntList class has no methods that allow the modification of the array and the array reference is not published to any other object, I am only wondering about visibility after construction.

Edit: Sorry, my class is not called String in my actual implementation. I changed the class name to IntList because there seems to be too much confusion.

Edit: The final answer I'll put here is Yes, the elements are visible.
@MikeClark found the JLS answer: JLS § 17.5 "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."

Thanks again!

Since you are populating the array in the constructor then yes, any call to new String(int[] array) will have the array initialized by the time it returns. The final keyword will also guarantee that the most recent changes to the array parameter at the time of assignment will be visible.

I found this is very helpful http://jeremymanson.blogspot.ch/2009/06/volatile-arrays-in-java.html So basically everything happens before volatile read is guaranteed to be seen by other threads. So there is some hack to make it happen. In addtion, jaa provide native AtomicReference/Long/Integer/...Array support. which will make sure update is visible to other threads.

A lot of distinct concepts seem to be mixed up in your question.

  • visibility and final have nothing to do with one another
  • visibility and threads have nothing to do with one another
  • a private variable is not visible outside the class to any other code, regardless of whether it is final
  • a final array can still have its elements changed. It is only the reference to the array itself that is final .

When you construct your IntList object (and by the way, thanks for changing the name) like this:

public IntList(int[] array) {
    this.array = array;
}

the internal this.array field references the same array object that was passed to the constructor. The array could still be modified from outside the String class:

int[] array = {1, 2, 3};
IntList list = new IntList(array);
System.out.println(Arrays.toString(list.readElements()); // prints [1, 2, 3]
array[1] = 0;
System.out.println(Arrays.toString(list.readElements()); // prints [1, 0, 3]

You can insulate your class from this by making a copy of the array in the constructor:

public IntList(int[] array) {
    this.array = Arrays.copyOf(array, array.length);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM