开发者

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

开发者 https://www.devze.com 2023-01-14 14:53 出处:网络
This question already has answers here: Closed 12 y开发者_高级运维ears ago. Possible Duplicate: Thread safety in Java class
This question already has answers here: Closed 12 y开发者_高级运维ears ago.

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?


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.


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.


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.


because number is not volatile, and getInt() is not synchronized, getInt() may return stale values. For more information, read about the java memory model.

0

精彩评论

暂无评论...
验证码 换一张
取 消