Reputation: 1495
Well, consider the immutable class Immutable
as given below:
public final class Immutable
{
final int x;
final int y;
public Immutable(int x,int y)
{
this.x = x;
this.y = y;
}
//Setters
public int getX()
{
return this.x;
}
public int getY()
{
return this.y;
}
}
Now I am creating an object of Immutable
in a class Sharable
whose object is going to be shared by multiple threads:
public class Sharable
{
private static Immutable obj;
public static Immutable getImmutableObject()
{
if (obj == null) --->(1)
{
synchronized(this)
{
if(obj == null)
{
obj = new Immutable(20,30); ---> (2)
}
}
}
return obj; ---> (3)
}
}
Thread A
sees the obj
as null
and moves into the synchronized block and creates object. Now, Since The Java Memory Model (JMM) allows multiple threads to observe the object after its initialization has begun but before it has concluded. So, Thread B
could see the write to obj
as occurring before the writes to the fields of the Immutable
. Hence Thread B
could thus see a partially constructed Immutable
that may well be in an invalid state and whose state may unexpectedly change later.
Isn't it making Immutable
non-thread-safe ?
EDIT
OK, After having lot of look up on SO and going thorough some comments,I got to know that You can safely share a reference to an immutable object between threads after the object has been constructed. Also, as mentioned by @Makoto, it is usually required to declare the fields containing their references volatile to ensure visibility. Also , as stated by @PeterLawrey , declaring the reference to immutable object as final
makes the field as thread-safe
Upvotes: 3
Views: 1621
Reputation: 106508
What you're describing here are two different things. First, Immutable
is thread safe if the operations are being done to an instance of it.
Thread safety is, in part, ensuring that memory isn't accidentally overwritten by another thread. Insofar as using Immutable
, you can never overwrite any data contained in an instance of it, so you can feel confident that, in a concurrent environment, an Immutable
object will be the same when you constructed it to when the threads are manipulating it.
What you've got right there is a broken implementation of double-checked locking.
You're right in that Thread A and Thread B may trample the instance before it's set, thus making the whole immutability of the object Immutable
completely moot.
I believe that the approach to fix this would be to use the volatile
keyword for your obj
field, so that Java (> 1.5) will respect the intended use of the singleton, and disallow threads to overwrite the contents of obj
.
Now, having read a bit closer, it seems to be a bit wonky that you'd have an immutable singleton that required two pieces of static data for it to exist. It seems more like this would be suited towards a factory instead.
public class Sharable {
private Sharable() {
}
public static Immutable getImmutableInstance(int a, int b) {
return new Immutable(a, b);
}
}
Every instance of Immutable
you get will truly be immutable - creating a new Immutable
has no impact on the others, and using an instance of Immutable
has no impact on any others as well.
Upvotes: 5
Reputation: 533870
So, Thread B could see the write to objas occurring before the writes to the fields of the Immutable. Hence Thread B could thus see a partially constructed Immutable that may well be in an invalid state and whose state may unexpectedly change later.
In Java 1.4, this was true. In Java 5.0 and above, final fields are thread safe after construction.
Upvotes: 8