[concurrency-interest] question the about the JMM

Brian Goetz brian at briangoetz.com
Wed Dec 5 17:26:05 EST 2007


> And making the variable volatile, or using it in a synchronized
> context should solve all problems, right?

Not sure about _all_ problems, but...

Making the flag volatile will ensure that writes to flag in setFlag()
are visible in something() ASAP.

> On Dec 5, 2007 10:56 PM, Brian Goetz <brian at briangoetz.com> wrote:
>>> 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.
>> I reviewed your colleague's e-mail again.  I had mistakenly switched the
>> positions: I thought _he_ was saying "there is a visibility problem" and
>> his colleague (you, apparently) that there was not.  But my intention
>> was to say "this code is broken", and the comments in the message should
>> make that clear.
>>
>> Unless something() is called from the same thread as setFlag(), it is
>> not guaranteed to _ever_ see flag be true unless it acquires the lock
>> acquired by the writing thread.
>>
>> Oh, and by the way, in:
>>
>>  >    synchronized (new Object()) {
>>  >      // unimportant
>>  >    }
>>
>> the synchronization has no effect in any case.  The compiler can prove
>> that no other thread could synchronize on the same object, and is thus
>> permitted to eliminate the sync entirely.
>>
>> On a tangentially related note, it is in very poor taste to forward a
>> private message to a public list without the author's permission; doubly
>> so because it was sent to someone else, not you.
>>
>>
>>
>>> 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
>>>>
>>> _______________________________________________
>>> Concurrency-interest mailing list
>>> Concurrency-interest at altair.cs.oswego.edu
>>> http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest



More information about the Concurrency-interest mailing list