[concurrency-interest] question the about the JMM

Peter Veentjer alarmnummer at gmail.com
Wed Dec 5 12:59:10 EST 2007


I'm having a discussion with a a very smart colleague about some
example (from iBatis) that in my opinion has a visibility problem and
in his opinion doesn't.

This is the example:

 private boolean flag = true;

 public void something() {
   if (flag) {
     synchronized (this) { // synchronized block
       // do something
     }
   } else {
     // do something else with very little impact, NOT inside a
 synchronized block
   }
 }

public void setFlag(boolean newFlag) {
   this.flag = newFlag;
   synchronized (new Object()) { // ANOTHER MONITOR THAN IN METHOD something
     // unimportant
   }
 }

With my current understanding of the JMM I would expect that the flag
variable has a visibility problem. Because there is no happens before
relation between the write in the setFlag method, and the read in the
something method, a thread that runs the something method doesn't need
to see the written value by a different thread ever.

The problem could be solved by using the the monitor lock rule (using
the lock of the object itself) or the volatile read/write rule. So the
simplest thing to remove the visibility problem is to make the flag
volatile.

The question is, am I correct? Does this example contain a visibility problem?

To make things more complicated, we have asked Brian Goetz and
according to him my colleague is right.

this is the mail conversion between them:

rom: Brian Goetz [mailto:brian at briangoetz.com]
Sent: Wed 12/5/2007 16:41
To: Erwin Bolwidt
Subject: Re: JMM question (wrt to a statement you made at JavaPolis)

Your colleague is wrong.

Both of the statements you refer to are correct.  The key is that only
synchronization actions (reads and writes of volatiles, and acquire and
release of locks) need to be totally ordered.  So if thread A release a
lock "before" thread B acquires one, that doesn't mean anything, because
the threads don't share your concept of "before".

The primary mistake people make in approaching concurrency is to falsely
assume "sequential consistency", meaning that "everything happens in a
fixed, global order".  In reality, it is more like the thought
experiments you did in special relativity, where ordering is relative to
the observer.  This happens in modern CPUs too, in the absence of
adequate synchronization.  The only total ordering you can rely on is
synchronization actions.  This is why if we synchronize on a common
lock, things work properly -- because it is sensible to speak of "when
you release the lock and I subsequently acquire it."  When we acquire
different locks, there is no way to guarantee "subsequent".  (And when
we don't acquire locks at all, it isn't even meaningful to talk about
"subsequent.")

Any logic that relies on unsynchronized reads of shared references to
mutable objects is committing the same error as double-checked locking,
with the same possible consequences.

The rules for the new memory model (happens-before) are actually fairly
simple to reason through.  Its the "I (think I) know what's going on in
the machine" part that leads people into trouble.  Such reasoning
invariably amounts to "I don't believe these are really the rules."

Erwin Bolwidt wrote:
> Hi Brian,
>
> A collegue and are having a discussion about one aspect of the new Java
> Memory Model.
> After one of your presentations on the JMM I asked you about how
> specific volatile or synchronized is (at JavaPolis I believe but it
> could have been JavaOne)
>
> Specifically, I wondered if synchronized on different monitors or access
> to different volatile variables were really independent: if these would
> only cause related data to be synchronized (written out to/invalidated
> L1/2 caches) with "global" memory or if they would effectively
> synchronize the whole thread state (caches) with "global" memory.
> You response as I remember it was that the latter was the case: the
> whole thread state (caches) would be synchronized. The former would be
> too complicated to implement.
>
> The JSR 133 FAQ (co-authored by you) at
> http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html states:
>
>         *Important Note:* Note that it is important for both threads to
>         synchronize on the same monitor in order to set up the
>         happens-before relationship properly. It is not the case that
>         everything visible to thread A when it synchronizes on object X
>         becomes visible to thread B after it synchronizes on object Y.
>         The release and acquire have to "match" (i.e., be performed on
>         the same monitor) to have the right semantics. Otherwise, the
>         code has a data race.
>
> Now I realize that possibly both statements are true, and that this
> boils down to a misunderstanding of terms like "happens-before
> relationship".
>
> I have an example and I'm not sure what would happen here. In the real
> case, "flag" was called "cacheEnabled" and the question was whether the
> cache could be turned off in a way that would be guaranteed to work.
> This looks a little like the double-check locking issue. My statement
> was that if "setFlag(false)" was called on one thread, the something()
> method on another thread would be guaranteed to see this
> _the_second_time_ the method was entered, because the synchronization
> would invalidate the CPU caches on the thread that runs something(), and
> likewise the synchronized on a different monitor in setFlag would write
> out the change to the field "flag" to global memory.
>
> My collegue disagrees. Can you tell who is right?
>
> Thanks a lot if you can spend some time on this.
>
> Regards,
>   Erwin Bolwidt
>
> -------------- Example code --------------
>
> private boolean flag = true;
>
> public void something() {
>   if (flag) {
>     synchronized (this) { // synchronized block
>       // do something
>     }
>   } else {
>     // do something else with very little impact, NOT inside a
> synchronized block
>   }
> }
>
> public void setFlag(boolean newFlag) {
>   this.flag = newFlag;
>   synchronized (new Object()) { // ANOTHER MONITOR THAN IN METHOD something
>     // unimportant
>   }
> }
>
>
> --
> Erwin Bolwidt
> business consultant
>


More information about the Concurrency-interest mailing list