Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this technically thread safe despite being mutable?

Yes, the private member variable bar should be final right? But actually, in this instance, it is an atomic operation to simply read the value of an int. So is this technically thread safe?

class Foo {
    private int bar;
    public Foo(int bar) {
        this.bar = bar;
    }
    public int getBar() {
        return bar;
    }
}

// assume infinite number of threads repeatedly calling getBar on the same instance of Foo.

EDIT:

Assume that this is all of the code for the Foo class; any threads with a reference to a Foo instance will not be able to change the value of bar (without going to such lengths as using reflection etc.)

like image 658
Finbarr Avatar asked May 05 '10 07:05

Finbarr


People also ask

Is mutable thread-safe?

So, it's thread-safe. Moreover, if MessageService were actually mutable, but multiple threads only have read-only access to it, it's thread-safe as well. As we can see, immutability is just another way to achieve thread-safety.

How can you tell if a thread is safe?

To test if the combination of two methods, a and b, is thread-safe, call them from two different threads. Put the complete test in a while loop iterating over all thread interleavings with the help from the class AllInterleavings from vmlens. Test if the result is either an after b or b after a.

Are immutable collections thread-safe?

Those objects should be immutable as well. Yes, they are thread safe.

What is immutable thread?

An immutable object is an object that is no longer modified once it has been constructed. If in addition, the immutable object is only made accessible to other thread after it has been constructed, and this is done using proper synchronization, all threads will see the same valid state of the object.


1 Answers

Final update: so my first conclusion happened to be right, just my reasoning was faulty :-( I re-edited my answer to make it somewhat coherent, not to hide the traces of my earlier blunder.

Conclusion

As @Wyzard pointed out, even though there is no way to change bar after construction, Foo is still not thread safe. The problem is not atomicity but visibility. If thread 1 is changing the value of bar in the constructor (from its default value of 0), there is no guarantee when other threads will get to see the new value (or whether they see it at all).

So foo looks like an immutable object. Quoting from Java Concurrency in Practice, section 3.4:

An object is immutable if:

  • Its state cannot be modified after construction;
  • All its fields are final; and
  • It is properly constructed (the this reference does not escape during construction).

Foo looks OK on 1) and 3), but not 2). And that is a crucial point, due to the reasoning above. Declaring a variable final is one way of ensuring its visibility between different threads. The other means are declaring bar volatile, or synchronizing its access method(s). But of course, in case of an immutable object, neither of these would make much sense.

Final Fields

So why do finalfields guarantee visibility? Answer from Java Concurrency in Practice, section 3.5.2:

Because immutable objects are so important, the JavaMemory Model offers a special guarantee of initialization safety for sharing immutable objects. As we've seen, that an object reference becomes visible to another thread does not necessarily mean that the state of that object is visible to the consuming thread. In order to guarantee a consistent view of the object's state, synchronization is needed.

Immutable objects, on the other hand, can be safely accessed even when synchronization is not used to publish the object reference. For this guarantee of initialization safety to hold, all of the requirements for immutability must be met: unmodi-fiable state, all fields are final, and proper construction. [...]

Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is not used to publish them.

This guarantee extends to the values of all final fields of properly constructed objects; final fields can be safely accessed without additional synchronization. However, if final fields refer to mutable objects, synchronization is still required to access the state of the objects they refer to.

And what happens if the field is not final? Other threads may silently see a stale value of the field. There is no exception or any kind of warning - that is one reason why these kinds of bugs are so difficult to trace.

like image 111
Péter Török Avatar answered Nov 11 '22 23:11

Péter Török