3

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

Mac
  • 1,711
  • 3
  • 12
  • 26
  • 4
    You could just write `public class Sharable { public static final Immutable obj = new Immutable(); }` It would be simpler and thread safe. – Peter Lawrey Aug 09 '14 at 23:24

2 Answers2

8

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.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Thanks Peter. So, it means that Immutable objects are not thread-safe inherently everywhere? They do need to be declared `final` to make them thread-safe in such cases? – Mac Aug 09 '14 at 23:27
  • If you are running Java 1.4, there could be a problem. Note: it is not guaranteed there will be a problem either. But you shouldn't be running such an old version. Use a current version and your Immutable will be immutable and thread safe. The fields need to be `final` to get this guarantee. – Peter Lawrey Aug 09 '14 at 23:32
  • I am fully agreed to your point. Please correct me if I am wrong.. `final` can make any object thread-safe over here (no matter it is immutable or not). If I am right then why is it mentioned in most of the sites and books that `immutable objects are inherently thread-safe in nature` ? – Mac Aug 09 '14 at 23:38
  • 1
    @mac that is an over simplification. Making a field final doesn't make the object referenced immutable, not does having an immutable object guaranteed thread safety. However, most developer use thread safe means of passing data between threads, e.g. a thread safe collection such as a BlockingQueue, and using this ensures a thread safe view of the object whether `final` is used or not. – Peter Lawrey Aug 09 '14 at 23:44
  • `not does having an immutable object guaranteed thread safety`.. This line is looking so tough to digest. As far as I know Thread safety means no data race .. no data race means Conflicting accesses of the same variable that are ordered by a happens-before relationship.. And happens-before means if write is done before read then read should see whatever is written by write operation. If I apply thread-safety concept on immutable objects then all above said should be true. But it is easily broken in code.. Then why is it said that "Immutable objects are inherently thread-safe"? – Mac Aug 10 '14 at 00:26
  • In the code that I have posted, object of `Immutable` is not published safely despite of being immutable in nature. It needs to be declared volatile explicitly. Declaring volatile even a mutable object would lead to the safe publication of object. Then what exactly is the reason and that immutable objects are said as thread-safe? – Mac Aug 10 '14 at 00:32
  • @Mac It is not easily broken in code, in fact you have to go out of your way to break an immutable, and you have to be running on a JVM which doesn't make non-final safe. In fact thread safety issues which are hard to detect worse in some ways. In any case, use a thread safe collection to pass data between threads and this is a non-issue. – Peter Lawrey Aug 10 '14 at 07:03
  • 1
    @Mac If everything you had was immutable you - by definition - would have a thread-safe program (obviously) - also a very boring one. The problem arrives as soon as we mix immutable and mutable data which at some level is required for you to do anything interesting. And there we can still have thread-safety problems even if immutable data is involved. That doesn't mean that immutability is useless - it allows us to limit the scope of where we have to worry about these issues at specific points in time. – Voo Aug 10 '14 at 14:39
  • Ok I went through your following answer in SO: http://stackoverflow.com/a/14653945/2536255 .. And there you have explicitly mentioned that : *You can safely share a reference to an immutable object between threads* **after the object has been constructed.** Can you please cite an official link for this ? Because, this single line is the one which is providing me the answer to my query. Please put this line and official link in your answer so that the OPs could directly read the correct answer (of course accepted one ;) ) in one go. Thanks. – Mac Aug 11 '14 at 01:03
  • @Mac If you share the object via a thread safe collection, and you have to go out of your want to avoid using one IMHO, it will be shared safely. I don't have a reference saying thread safe collections are thread safe, I would hope you would accept that. ;) – Peter Lawrey Aug 11 '14 at 06:11
  • Perfect words @PeterLawrey ;).. thanks.. Accepting your answer. And I have posted one comment in your answer at stackoverflow.com/a/14653945/2536255 .. Can you please clarify my doubt over there? – Mac Aug 11 '14 at 06:57
  • 2
    @Mac: you seem to ask for [this specification](http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5) – Holger Aug 11 '14 at 10:44
  • 1
    A reference on the extended thread safety guarantees offered by `java.util.concurrent` and mentioned by @PeterLawrey above can be found in the "Memory Consistency Properties" section [here](https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/util/concurrent/package-summary.html). – Asa Nov 12 '22 at 21:56
5

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.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • Thanks @Makoto. That typo is corrected :). I repeat the same comment as I mentioned in @Peter Lawrey answer. So, it means that Immutable objects are not thread-safe inherently everywhere? They do need to be declared `final` or `volatie` to make them thread-safe in such cases? – Mac Aug 09 '14 at 23:33
  • 2
    Again, what you're doing here is double-checked locking for a singleton. The debate around whether or not `Immutable` is truly immutable is thrown out the window if the class using it doesn't use it in a thread-safe manner. If you assign an immutable object to a mutable reference, then that reference is still not thread safe. Don't conflate immutability with thread safety. – Makoto Aug 09 '14 at 23:36
  • I am reading your answer and comment again and again but I am still not able to make out why Immutable objects are called as inherently thread-safe if there thread safeness is broken vaguely in code.. In what context this thread-safety is discussed for the immutable objects.. – Mac Aug 10 '14 at 00:21
  • In the code that I have posted, object of `Immutable` is not published safely despite of being immutable in nature. It needs to be declared volatile explicitly. Declaring volatile even a mutable object would lead to the safe publication of object. Then what exactly is the reason and that immutable objects are said as thread-safe? – Mac Aug 10 '14 at 00:30
  • @Mac there's a subtle distinction here. In the code posted above, the instance of `Immutable` will be published safely, but `Sharable`'s reference, called `obj` is not published safely. The instance is different from a reference to the instance. Here, the instance of `Immutable` will always be seen in a consistent state across threads (both fields will be fully initialised), but the reference `obj`, may be seen in an inconsistent state (null or a valid reference). Does that make more sense? – Grundlefleck Aug 10 '14 at 20:09
  • @Grundlefleck Thanks for putting light on it. Please correct me if I am wrong in my understanding about publication, It is only the object which is published, reference variable is just a mean to publish that object.... And regarding instance of Immutable being seen in a consistent state all times... I doubt about this.. Because as I told in my post .. **since java allows the object to be visible after the initialization is begun but before it is concluded**.. so it is possible that thread B might see the Immutable object in inconsistent state.. – Mac Aug 10 '14 at 20:26
  • 1
    @Mac "since java allows the object to be visible after the initialization is begun but before it is concluded" this is what the final fields of immutable objects give you. Quoting JCIP (section 3.5.2): "Immutable objects ... can be safely accessed even when synchronization is not used to publish the object reference." If you take the `final` modifiers away from `Sharable`'s fields, the fields themselves could then be seen in an inconsistent state, e.g. `x` could be observed as `0` then later as whatever int is assigned to it. – Grundlefleck Aug 12 '14 at 08:16