java.lang.String is only effectively immutable. Brian Goetz of "Java Concurrency in Practice" said something like effectively immutable objects will only be thread safe if safely published. Now, say I unsafely publish String like this:
public class MultiThreadingClass {
private String myPath ="c:\\somepath";
//beginmt runs simultaneously on a single instance of MultiThreading class
public void beginmt(){
Holder h = new Holder();
h.setPath(new File(myPath)); //line 6
h.begin();
}
}
public class Holder {
private File path;
public void setPath(File path){
this.path = path;
}
public void begin(){
System.out.println(path.getCanonicalPath()+"some string");
}
}
At the moment that the MultiThreadingClass is initializing with its constructor, it could happen that the File constructor on line 6 may not see the value of myPath.
Then, about three seconds after the construction of the unsafely published String object, threads on MultiThreadingClass are still running. Could there still be a chance that the File constructor may not see the value of myPath?
Your statement that you are asking your question about:
The answer is complicated. You don't need to worry about the char-array
value
inside theString
object. As I mentioned in the comments, because it is afinal
field that is assigned in the constructors, and becauseString
doesn't pass a reference to itself before assigning thefinal
field, it is always safely published. You don't need to worry about thehash
andhash32
fields either. They're not safely published, but they can only have the value 0 or the valid hash code. If they're still 0, the methodString.hashCode
will recalculate the value - it only leads to other threads recalculating the hashCode when this was already done earlier in a different thread.The reference
myPath
inMultiThreadingClass
is not safely published, because it is notfinal
. "At the moment that the MultiThreadingClass is initializing with its constructor", but also later, after the constructor completed, other Threads than the thread that ran the constructor may see the valuenull
inmyPath
rather than a reference to your string.There's an example in the Java Memory Model section of the Java Language Specification [version 8 linked but this is unchanged since JMM was released in JSR-133]:
This is even likely to happen on a heavily loaded machine with many threads.
Workarounds/solutions:
myPath
afinal
field (and don't add constructors that pass out thethis
reference before assigning the field)myPath
avolatile
fieldmyPath
synchronize on the same monitor object before accessingmyPath
. For example, by makingbeginmt
asynchronized
method, or by any other means.