Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java concurrency - why doesn't synchronizing a setter (but not a getter) make a class thread-safe? [duplicate]

Possible Duplicate:
Thread safety in Java class

I'm reading Java concurrency in Practice, and I've come to an example that puzzles me.

The authors state that this class is not threadsafe

public class MutableInteger {

    private int number;

    public int getInt() {
        return number;
    }

    public void setInt(int val) {
        number = val;
    }
}

And they also state that synchronizing only one method (the setter for example) would not do; you have to syncronize both.

My question is: Why? Wouldn't synchronizing the setter just do?

like image 690
Pablo Fernandez Avatar asked Sep 01 '10 07:09

Pablo Fernandez


People also ask

Do getters () and setters () require synchronization?

To elaborate, if one wants to obtain the most recent version of value in a multi-threaded application, both the getter and setter should be synchronized.

Do getters need to be synchronized?

When one part of a getter/setter pair is synchronized the other part should be too.

What is the problem with synchronization in Java?

Synchronization can result in hold-wait deadlock where two threads each have the lock of an object, and are trying to acquire the lock of the other thread's object. Synchronization must also be global for a class, and an easy mistake to make is to forget to synchronize a method.

Is getter setter thread safe?

Depends on the particulars. It is important to realize that synchronization does two important things. It is not just about atomicity but it is also required because of memory synchronization. If one thread updates the a field, then other threads may not see the update because of memory caching on the local processor.


3 Answers

Java has a happens before/happens after memory model. There needs to be some common concurrent construct (e.g. synchronized block/method, lock, volatile, atomic) on both the write path and the read path to trigger this behaviour.

If you synchronize both methods you are creating a lock on the whole object that will be shared by both the read and write threads. The JVM will ensure that any changes that occur on the writing thread that occur before leaving the (synchronized) setInt method will be visible to any reading threads after they enter the (synchronized) getInt method. The JVM will insert the necessary memory barriers to ensure that this will happen.

If only the write method is synchronized then changes to the object may not be visible to any reading thread. This is because there is no point on the read path that the JVM can use to ensure that the reading thread's visible memory (cache's etc.) are in line with the writing thread. Make the getInt method synchronized would provide that.

Note: specifically in this case making the field 'number' volatile would give the correct behaviour as volatile read/write also provides the same memory visibility behaviour in the JVM and the action inside of the setInt method is only an assignment.

like image 108
Michael Barker Avatar answered Oct 17 '22 17:10

Michael Barker


It's explained in the book before the sample (page 35):

"Synchronizing only the setter would not be sufficient: threads calling get would still be able to see stale values."

Stale data: When the reader thread examines ready, it may see an out-of-date value. Unless synchronization is used every time a variable is accessed, it is possible to see a stale value for that variable. Worse, staleness is not all-or-nothing: a thread can see an up-to-date value of one variable but a stale value of another variable that was written first.

like image 5
Soundlink Avatar answered Oct 17 '22 19:10

Soundlink


If you only Synchronize the setter method, you could only guarantee the attribute would not be amended incorrectly, but you could not be sure it is stale value when you try to read the variable.

like image 1
Wei S Avatar answered Oct 17 '22 18:10

Wei S