Reputation: 169
Brian Goetz in his article from https://www.ibm.com/developerworks/java/library/j-jtp06197/
uses the example pasted below as a cheap read-write lock. My question is that if the int variable value is not declared volatile then would it make a difference? My understanding is that since the writes to value are done within a synchronized block so latest value will be visible to other threads any way and therefore declaring it volatile is redundant. Please clarify?
@ThreadSafe
public class CheesyCounter {
// Employs the cheap read-write lock trick
// All mutative operations MUST be done with the 'this' lock held
@GuardedBy("this") private volatile int value;
public int getValue() { return value; }
public synchronized int increment() {
return value++;
}
}
Upvotes: 2
Views: 384
Reputation: 169
Thanks very much for the answers guys. Found this on oracle website as well now: "Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object." https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
Upvotes: 0
Reputation: 178263
My understanding is that since the writes to value are done within a synchronized block so latest value will be visible to other threads any way
This is incorrect. Generally, there is no guarantee that other threads "see" changes to variables as soon as the change is made. A thread may see a stale value for a changed variable because, e.g. the thread sees the value really in a register instead of main memory.
A volatile
variable establishes "happens-before" semantics. The JLS, section 17.4.5, states:
Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.
- A write to a
volatile
field (§8.3.1.4) happens-before every subsequent read of that field.
The JLS, Section 8.3.1.4:
A field may be declared
volatile
, in which case the Java Memory Model ensures that all threads see a consistent value for the variable (§17.4).
The reason that the field must be volatile
is that even though the read is atomic, it needs to ensure that the value is current -- that any value previously written by another thread is visible. The read being atomic is not enough; volatile
is still necessary to ensure consistency of the value.
Upvotes: 1
Reputation: 4959
public synchronized int increment()
This synchronized
prevents you from skipping an increment if two threads or more were trying to increment at the same time (because ++
is not atomic).
private volatile int value
This prevents you from seeing an outdated value in one thread which was already incremented in another thread. (Note that we could also have made getValue synchronized to achieve this)
Upvotes: 0