Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does volatile influence non-volatile variables?

Okay, suppose I have a bunch of variables, one of them declared volatile:

int a;
int b;
int c;
volatile int v;

If one thread writes to all four variables (writing to v last), and another thread reads from all four variables (reading from v first), does that second thread see the values written to a, b and c by the first thread, even though they are not themselves declared volatile? Or can it possibly see stale values?

Since there seems to be some confusion: I'm not deliberately trying to do something unsafe. I just want to understand the Java memory model and the semantics of the volatile keyword. Pure curiosity.

like image 634
fredoverflow Avatar asked May 29 '11 11:05

fredoverflow


2 Answers

I'm going to speak to what I think you may really be probing about—piggybacking synchronization.

The technique that it looks like you're trying to use involves using one volatile variable as a synchronization guard in concert with one or more other non-volatile variables. This technique is applicable when the following conditions hold true:

  • Only one thread will write to the set of values meant to be guarded.
  • The threads reading the set of values will read them only if the volatile guard value meets some criteria.

You don't mention the second condition holding true for your example, but we can examine it anyway. The model for the writer is as follows:

  • Write to all the non-volatile variables, assuming that no other thread will try to read them.
  • Once complete, write a value to the volatile guard variable that indicates that the readers' criteria is met.

The readers operate as follows:

  • Read the volatile guard variable at any time, and if its value meets the criteria, then
  • Read the other non-volatile variables.

The readers must not read the other non-volatile variables if the volatile guard variable does not yet indicate a proper value.

The guard variable is acting as a gate. It's closed until the writer sets it to a particular value, or set of values that all meet the criteria of indicating that the gate is now open. The non-volatile variables are guarded behind the gate. The reader is not permitted to read them until the gate opens. Once the gate is open, the reader will see a consistent view of the set of non-volatile variables.

Note that it is not safe to run this protocol repeatedly. The writer can't keep changing the non-volatile variables once it's opened the gate. At that point, multiple reader threads may be reading those other variables, and they can—though are not guaranteed—see updates to those variables. Seeing some but not all of those updates would yield inconsistent views of the set.

Backing up, the trick here is to control access to a set of variables without either

  • creating a structure to hold them all, to which an atomic reference could be swapped, um, atomically, or
  • using a lock to make writing to and reading from the entire set of variables mutually exclusive activities.

Piggybacking on top of the volatile guard variable is a clever stunt—not one to be done casually. Subsequent updates to the program can break the aforementioned fragile conditions, removing the consistency guarantees afforded by the Java memory model. Should you choose to use this technique, document its invariants and requirements in the code clearly.

like image 179
seh Avatar answered Oct 13 '22 01:10

seh


Yes. volatile, locks, etc., setup the happens-before relationship, but it affects all variables (in the new Java Memory Model (JMM) from Java SE 5/JDK 1.4). Kind of makes it useful for non-primitive volatiles...

like image 22
Tom Hawtin - tackline Avatar answered Oct 12 '22 23:10

Tom Hawtin - tackline