Java Array Synchronization (Visibility)
Asked Answered
R

3

11

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!

Rollin answered 20/11, 2012 at 19:45 Comment(10)
please don't call your classes as built-in classes. String clashes with java.lang.String - and may cause you no end of problems.Transistor
field visibility and threads are orthogonal notions. Visibility is only related to where your code is, where the field is, and what are the modifiers, not to which thread executes the codeTrafficator
what package are you running that from?Transistor
@SamuelRossille "visibility" is a term often used when discussing the [Java] memory model, which is a topic highly relevant to multithreading. See, for example, this discussion of the Java Memory Model leading up to the revised Java 5 JMM: ibm.com/developerworks/library/j-jtp03304. "One of the key concepts needed to understand the JMM is that of visibility -- how do you know that if thread A executes someVariable = 3, other threads will see the value 3 written there by thread A?"Sour
@SamuelRossille Unless you're talking about visibility of stack variables (which he sort of is) and reference publishing (also sort of related), in which case it's definitely applicable to threads.Profusion
Also, thank you for changing the name of your class. It confuses all the people with ~100 rep that don't read the questions into thinking you mean java.util.String, and it just makes answering these questions a nightmare. +1Profusion
@MikeClark - "Visibility" is an overloaded term. When talking about the Java language (as opposed to the Java memory model) it usually refers to the access modifiers (public, private, etc.)--as in "Let's look at a collection of classes and see how access levels affect visibility."Heptahedron
@TedHopp - the term "visibility" is also used heavily when referring to changes made across threads. see here: docs.oracle.com/javase/specs/jls/se5.0/html/memory.htmlFrei
@MikeClark - you should make your comment an answer since none of the current answers gets it quite right.Frei
@MikeClark and Brian I didn't know that meaning of visibility. Ignorance caused my mistake. Tx for the information.Trafficator
S
2

Since you are populating the array in the constructor then yes, any call to new IntList(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.

Scincoid answered 20/11, 2012 at 19:48 Comment(13)
there is no such constructor String(int[])Hemophilia
@EvgeniyDorofeev - There is in OP's class. (It's not java.lang.String.)Heptahedron
Yes, I understand that if i populated the array in the constructor it will be visible to other threads but the point was that I am populating the array before the constructor and simply setting the rerference in the constructor.Rollin
Exactly, so by the time the reference is set in the constructor the array is already populated, it's the same concept exactly.Scincoid
And since you have it marked final you can guarantee that the reference will never change (individual array elements can be modified later of course)Scincoid
Thanks! This answers my question exactly.Rollin
@Rollin - it may answer your question, but it doesn't explain "why" (i.e. the special memory effects that the "final" modifier has).Frei
AFAIK, final doesn't have any impact on OP's question. The reference is set before the new object is returned regardless, right?Scincoid
Yes, my may have been a bit confusing but all I wanted to know was if the elements inside the array would be visible to other threads after the construction of class.Rollin
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."Sour
I was also assuming the elements in the array did not change by any means after the construction of the class.Rollin
So as a practical example of this, if the OP had some other thread possibly modifying the array instance that was passed in, the final keyword will provide an added benefit that the very latest values of that array will be visible. Makes sense. That doesn't seem to be the case for the example OP presented here though.Scincoid
@Frei how is that not what I said in the comment right before yours? If thread X modifies array before the constructor is called, the final keyword ensures that those changes are visible when the assignment is made. What am I missing?Scincoid
K
0

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.

Kinchen answered 20/12, 2016 at 5:36 Comment(0)
H
-3

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);
}
Heptahedron answered 20/11, 2012 at 19:51 Comment(5)
But final does have to do with memory visibility. See e.g. cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRight Also the JLS § 17.5 "final fields also allow programmers to implement thread-safe immutable objects without synchronization. A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads." The OP is clearly talking about memory visibility, not lexical visibility (scoping).Sour
@MikeClark Of course, not to be misleading, a final array is not immutable. The only way to ensure immutability of an array is to use scoped visibility so that the public access can be made to return copies.Profusion
@Profusion A good point. A Java array is mutable, and so care must be taken. However, final can be used to make guarantees about the visibility of the contents of an array, if used with careful attention to the constraints of the JLS: "[Another thread] 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."Sour
@MikeClark - OP did not say "memory visibility"; it seems to me to be a question about whether array elements can be changed once the object is constructed. The Java Language Specification defines "visible" in terms of scoping: "A declaration d is said to be visible at point p in a program if the scope of d includes p, and d is not shadowed by any other declaration at p." This has nothing to do with the memory model.Heptahedron
@TedHopp He did not say "memory visibility", but he clearly implied it. His statement "I am wondering if the elements in the IntList are guaranteed to be visible by other threads". This exactly the kind of question the Java Memory Model sets out to answer. I agree "visibility" is an overloaded term, and without any other contextual clues I would assume the term "visibility" refers to scoping. But his mention of threading and specifically data visibility to other threads put his question firmly in the arena of memory visibility, not scoping.Sour

© 2022 - 2024 — McMap. All rights reserved.