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
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;
}
}
If lastConstructed was volatile but then the reference was unsafely
published to another thread, then the String would not be immutable.
Right?
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.