Immutability doesn’t guarantee thread safety

With the introduction of the new Java Memory Model (JMM) in Java 5 (JSR-133) a lot of unclearities have been removed from Java regarding immutable classes and thread safety. Under the new JMM it is now perfectly clear that the immutable nature of a class doesn’t guarantee that it is thread safe. Take a look at the following class:

public class MyInt{
    private int x;

    public MyInt(int y){
        this.x = y;
    }

    public int getValue(){
        return x;
    }
}

Reorderings and Visibility

MyInt is not thread safe by nature, even though it is immutable. I hope you wonder why. To understand what can go wrong, I have to introduce 2 concepts:

  1. reorderings: the compiler (Javac, JIT, CPU etc) is allowed to reorder instruction to improve performance. To name a few techniques that rely on reordering:
    1. locality: reads/writes to variables can be grouped to increase the chance of cache hit
    2. dynamic scheduling: to prevent that a CPU has to wait (and do nothing) for instructions in the pipeline (maybe memory access is delaying), it can execute unrelated instructions.

    There are more techniques, and you are never sure which techniques are used because Java is platform independent. You just need to remember that instructions can be reordered unless this is prevented.

  2. visibility: inside a single thread all reads/writes to a variable need to be visible, but no guarantees are made with normal variables that changes made in by some thread to a variable, are visible in another thread. Only when there is a happens-before edge between a write and a read, you are sure that the change is visible. The reason why this strange behavior exists is performance. Because of the strong memory coherence most CPU have, visibility problems normally won’t occur that often.

So what can go wrong with MyInt?

Constructors are not treated special by the compiler (JIT, CPU etc) so it is allowed to reorder instructions from the constructor and instructions that come after the constructor. In the case of the MyInt it is allowed that the assignment of a newly created instance of of MyInt is assigned to a variable before the constructor has run. This reordering is never visible in the executing thread (within-thread if-serial semantics), but if another thread is going to read x, it could see a partially created MyInt and sees 0 (the default value of an int member variable) at one moment, and the next moment it sees the correct value for x. This problem can be fixed by making x final because this prevents reordering. Under the old JMM, making the field final even is not a solution.

Another problem is that the write to x by the constructing-thread, and the read from x by another thread, doesn’t need to have a happens-before edge. If this edge is missing, no guarantees are made that a change made in one thread, is visible in another thread (in other words, x is not safely published). The consequence is that the other thread doesn’t need to see the constructed value (ever!) and still sees the initial value. This visibility problem can be solved by making x final (volatile would also be a working solution).

Conclusion

Not all immutable classes are thread safe by definition, only proper created ones are. The simplest thing that can be done is making variables final, if these can be set in the constructor. In case of setters, reordering and visibility problems can be prevented by making the field volatile or make sure that the field is always used in a synchronized context (eg synchronized getter/setter or a Lock).

The new JMM has a new and very useful property: save hand off. It allows objects with visibility and reordering issues to be used safely in a multi threaded environment because reorderings and visibility problems are prevented. Not properly created immutable classes can be passed through such a structure without worrying about these issues. But if you have the chance, try to do it good from day one.

If you want to learn more about the JMM, I suggest reading “Java Concurrency in Practice”.

14 Responses to “Immutability doesn’t guarantee thread safety”

  1. Jeremy Weiskotten Says:

    I second the recommendation for “Java Concurrency in Practice” (by Brian Goetz). It’s THE book on the concurrency API.

    For this example, to make it truly immutable, the class should be declared final in addition to the instance variable x. Otherwise it could be subclassed and made mutable.

  2. Mikael Grev Says:

    If you want to read up on the mutability/immutability in practical terms I’ve written a little article about it a while ago: http://www.javalobby.org/articles/immutable/index.jsp

  3. Vijay Says:

    I think that the following class is immutable and Thread-safe in Java 5.0 and higher:

    public class MyInt{
    private final int x;

    public MyInt(int y){
    this.x = y;
    }

    public int getValue(){
    return x;
    }
    }

  4. Nils Says:

    Sounds to me like Java’s Threading model is terribly broken. A high-level language should hide such low-level details.

  5. TBD » interesting article “Immutability doesn’t guarantee thread safety” Says:

    [...] out this interesting post Immutability doesn’t guarantee thread safety I guess we all have to worry about thread even corrupting our data (even more then [...]

  6. Simon P. Chappell Says:

    Your example object is not immutable. Make the private attribute final as well. No need to make the class final, that is an unfortunate overloading of the final keyword. If you were storing any objects rather than basic types, you’d also have to worry about cloning. Immutability is wonderful, but it’s not as easy as it initially looks. :-)

  7. TBD2 Says:

    Is this new to anybody?! This has been a problem for years and anybody who hasn´t been aware of it shouldn´t be writing serious apps. There are numerous articles on this subject. See http://www.javaworld.com/jw-02-2001/jw-0209-double.html (from 2001)

  8. pveentjer Says:

    It is not new to me, but it appears that not everybody knows it. That is why I decided to create a blogpost about it. I think that 99% of the developers are totally unaware of the JMM.

  9. ray Says:

    The example is not appopriate. It breaks one of the definition of immutable class. The attribute of an immutable class has to be ‘final’. Immutable class is thread safe, period.

  10. pveentjer Says:

    Hi Ray, thanks for your reply

    It depends on the definition of immutable and not everyone agrees with this definition. In most cases I prefer using final fields, but in some cases it is not very practical because of too complex constructors. In these cases I use default values and setters for these fields.

    After the object has been constructed (and maybe a few setters are called) the object can be considered immutable because the state isn’t going to change (for example an EmployeeManager

    And from a single threaded point of view, the example I have given is immutable. Within that thread it is impossible to change the value or to see an inconsistent value (within-thread if-serial-semantics).

  11. Chris Says:

    Very nice blog and site.
    Thanks Peter for reminding me of this subtle issue. Especially, reorderings and the final keyword for private int x. It was new to me.

  12. Ferdhz Says:

    Thanks for enlightening me! I’m totally unaware of the JMM and its effects on my real-time applications. I think i have to get a copy of “Java Concurrency in Practice” book.

  13. Attilio Says:

    Very interesting issue. Thank you for your detailed explanation.
    I think I will never learn enough about concurrency.

  14. Khl Says:

    a good article,
    have just aremark:”Reorderings and Visibility” would be clear to name it “Reordering and Isolation”

Leave a Reply