Javadee
Javadee

Reputation: 169

redundant volatile in cheap read-write lock?

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

Answers (3)

Javadee
Javadee

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

rgettman
rgettman

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

Patrick Parker
Patrick Parker

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

Related Questions