Mac
Mac

Reputation: 1495

Does immutability guarantee thread safety?

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 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.

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

Answers (2)

Makoto
Makoto

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

Peter Lawrey
Peter Lawrey

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

Related Questions