Reputation: 14126
A note from the The Java Concurrency In Practice
Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is not used to publish them
What I get is that they are thread - safe.
A snippet from Jeremy Manson blog-
class String {
// Don't do this, either.
static String lastConstructed;
private final byte[] bytes;
public String(byte[] value) {
bytes = new byte[value.length];
System.arraycopy(value, 0, bytes, 0, value.length);
lastConstructed = this;
}
}
Since the this reference is being stored in lastConstructed" hence Escaping the constructor
Ofcourse, it would work if you made lastConstructed volatile (postJDK5+ semantics)
One of the questions asked there is-
If lastConstructed was volatile but then the reference was unsafely published to another thread, then the String would not be immutable. Right?
to which Jeremy's reply was-
It wouldn't be thread-safe because it was immutable, but it would be thread-safe because lastConstructed was volatile.
I perfectly understand that it would be thread-safe because lastConstructed was volatile, but I don't get It wouldn't be thread-safe because it was immutable.
Why? The note from Concurrency In Practice says Immutable objects can be used safely by any thread (i.e Thread Safety guarantee). If something is immutable, then it is thread safe.
Please suggest.
Upvotes: 1
Views: 543
Reputation: 6197
Though @Peter Lawrey has explained the details and problems of designing thread safe and immutable classes, and based on the further discussion, I think the question hasn't received the direct answer. So, I'd like to elaborate a bit:
The main problem in the understanding the phrase "Immutable objects can be used safely by any thread" is that it's not complete per se. It relies on the premise that any object must also be safely published to be thread-safe. Immutable objects is not an exception. So, the full phrase should be "Immutable and safely published objects can be used safely by any thread."
The problem in the String
example is that it allows the reference to the object to escape from the constructor, thus presenting to other threads potentially invalid object state. For instance, if the compiler decides to optimize the constructor and rearrange operations for performance reasons this way:
public String(byte[] value) {
bytes = new byte[value.length];
lastConstructed = this;
System.arraycopy(value, 0, bytes, 0, value.length);
}
some other thread that reads lastConstructed
will be able to see the string that is not fully constructed. So, the class is not thread safe, even though its instances are immutable.
Here we come to the meaning of the phrase "It wouldn't be thread-safe because it was immutable". It means that immutability alone doesn't guarantee thread safety and the example proves it.
Making lastConstructed
volatile would force the compiler to emit a memory barrier that would prevent the optimizer from rearranging operations in the way described above. It would guarantee that the array copying always happens before the assigning lastConstructed = this
. As the result, another thread, that reads lastConstructed
, would never see an underconstructed string. It would also guarantee that other threads would always read the actual value of lastConstructed
. Thats why "it would be thread-safe because lastConstructed was volatile" in this particular case.
Upvotes: 2
Reputation: 533492
A common mis-understanding is that you have Object fields in Java. You only have references and primitives. This means that
static String lastConstructed;
The field lastConstructed
is a mutable reference. It's visibility is not thread safe. Having an immutable object doesn't confer any properties on a reference to that object.
Similarly if you have a final
field, this doesn't make your Object immutable.
final Date today = new Date();
today
is not immutable just because you made one reference to it final
.
A more subtle on is in the use of volatile
You have to be careful as to whether you are reading or write the volatile value. Even if you do
volatile Date now = new Date();
now.setTime(System.currentTimeMillis()); // no thread safe.
There is two reasons this is not thread safe. 1) The access to now
is a read not a write and secondly it occurs before the write in any case. What is required is a write barrier after. Something you see what appears to be nonsense.
now = now; // this adds a write barrier.
A related myth is that if you use a thread safe collection, any series of operations you perform is also thread safe. It's a bit like fairy dust, you just sprinkle it around and many of your bugs disappear, but this doesn't mean you really are thread safe.
In short, thread safety is like a chain of dependencies, if any aspect of how data is accessed is not thread safe, none of it is.
Note: adding some thread safe constructs can hide thread safety issues, but it doesn't fix them, it just means that some change in JVM, or OS or hardware will break your code in the future.
Upvotes: 1