[concurrency-interest] Volatile / Sychronized?

First Last chancer357 at hotmail.com
Tue Dec 19 21:16:22 EST 2006


Please clear up something about the proper use of volatile for me. I'm 
having difficulty understanding when volatile is sufficent. Its a tricky 
thing to explain, so let me just show my confusion with a few examples and 
citations.

Question #1:

I see many examples of code such as this, taken from the JMM FAQ on Bill's 
site:

class VolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    v = true;
  }

  public void reader() {
    if (v == true) {
      //uses x - guaranteed to see 42.
    }
  }
}

This is very clear to me. Marking the boolean field volatile is enough to 
effect the memory barrier/establish the happens-before relationship needed 
to make the order. The description of volatile being half-synchonized is 
very good.

Following this example in the JMM FAQ is the statement:

"Important Note: Note that it is important for both threads to access the 
same volatile variable in order to properly set up the happens-before 
relationship. It is not the case that everything visible to thread A when it 
writes volatile field f becomes visible to thread B after it reads volatile 
field g. The release and acquire have to "match" (i.e., be performed on the 
same volatile field) to have the right semantics."

What does this mean? Should I take this to mean that the following example 
won't work?

class BadUseOfVolatileExample {
  volatile int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    v = true;
  }

  public void reader() {
    if (v == true) {
      //uses x - guaranteed to see 42.
    }
  }
}

If it is true the example above won't work, why does it work when x
is not volaitle. If it is false that the example won't work, can you please
show me an example that demonstrates the pitfall the Important Note
warns us of? Along with an explaination of why it is so?

Question #2:

I have often seen a poor man's synchonized implemented as such
(though I am admitedly having trouble locating a concrete example of
this as present. I could have sworn this has appeared on this list before,
but there is no search function on mailman..)

class SynchronizedVolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    synchronized(this) {
      v = true;
    }
  }

  public void reader() {
    if (v == true) {
      //uses x - guaranteed to see 42.
    }
  }
}

What I am trying to illustrate here with this poorly chosen example
is a situation in which a voliatle field is used, but is only ever written
to from within a synchronized block, and is read w/o the synchronzation.

Is this neccessarry in this example? If not what sort of situation is it 
neccessary
in? I could rephrase this whole question as, "Is there ever a circumstance 
where
a volaitle variable must be written to from within a synchronized block?" 
(and if so
please demonstrate the pitfall for my understanding.

Question #3:

I have seen it suggested that one scenario which the synchronized is 
required
would be to ensure the completion of a constructor before the assignment. 
The
fear being that w/o the synchronized keyword, its possible to somehow have
assigned the buffer reference to a StringBuffer object whose constructor has
not completed, or whose internal fields that are not volatile themselves may
not be visible to other threads.

class VolatileStringBufferExample {
  volatile StringBuffer buffer = new StringBuffer();
  public void swapInNewBuffer() {
    synchronized(this) {
      buffer = new StringBuffer();
    }
  }
  public StringBuffer getStringBuffer() {
    return buffer;
  }
}

Is this a valid concern, or does a constructor give you a happens-before 
garuntee?

Question #4:

Is there any use for AtomicBoolean or AtomicReference if we don't care about 
CAS semantics?
In other words, if all I want is to not use the word synchronized is all I 
need to do add "volatile",
kick back and enjoy?

Question #5:

How much am I saving by dropping synchronized keywords anyways? I've heard 
things like JSE5
and JSE6 are just a lot better at optimizing locks. That sounds great, but I 
can't quantify this kind
of assement. Does this mean its half as slow as it used to be? Does this 
mean its 2 times worse than
using a synchronized keyword? Does it mean there could theoretically be no 
locking at all because through some magic the JVM has optimized away the 
lock?

If I give up the relative clarity of happens-before relationships I can 
establish with a synchronized
keyword, I want to know how much I am giving up. Some developers I work with 
shudder as soon
as they see the word synchronized and I really don't have a good way to 
gauge the reality of
their concerns. Certainly there are scenarios in which fine grained locks, 
or lock-free algorithms are a boon - but that doesn't mean ALL 
synchronization is evil.

On a similar note, what is the cost of volatile field access? Compared to 
regular field access? There
must be something going on to ensure the happens-before relationships hold - 
and it can't be free
but again its one of those things I'm more generally assured the JVM is 
"better" at doing than it
used to be.

(And here by better, I mean articles, blog entries, sun docs, etc. The only 
source I do not have
at hand currently is Brian's newer book)

---

I thank you for any light you may shed on these mysteries for me, and you 
have my apologies if I repeat myself. It could be worthwhile to create 
examples, good & bad, to better demonstrate these points if I'm not just 
totally missing something already documented. Maybe as an appendix to
the JMM FAQ, or an addtion to the java.util.concurrent.package.html.

_________________________________________________________________
Get FREE Web site and company branded e-mail from Microsoft Office Live 
http://clk.atdmt.com/MRT/go/mcrssaub0050001411mrt/direct/01/



More information about the Concurrency-interest mailing list