[concurrency-interest] Reordering clarification in DCL example

Joe Bowbeer joe.bowbeer at gmail.com
Sat May 2 13:12:32 EDT 2009

On Sat, May 2, 2009 at 9:38 AM, Tim Peierls wrote:

> See more recent discussions in Java Concurrency in Practice, Section 16.2.4
> and Effective Java, 2nd edition, Item 71.
> The fixed version of the code is:
> class SomeClass {
>   private volatile Resource resource;
>   public Resource getResource() {
>     Resource tmp = resource;
>     if (tmp == null) {
>       synchronized (this) {
>         tmp = resource;
>         if (tmp == null)
>           resource = tmp = new Resource();
>       }
>     }
>     return tmp;
>   }
> }
> --tim

A clarification of "fixed" that I think Tim would agree with:

"Fixed" is used in the sense that if you have to have double-check locking,
presumably for performance reasons, then this is one of the very few ways to
code it correctly.

On the other hand, this "fix" adds even more surface area to the code, and
more modifiers for maintainers to contemplate ("volatile"), so as with all
optimizations, it is best avoid going this route unless you really need it.

Compiler: In JMM and DCL discussions, the "compiler" refers to javac plus
JIT plus anything else that reorders or optimizes at the instruction level.
In addition to the compiler(s), the processors and memory system (and
anything that might be rigged to run Java apps), can reorder operations --
but only to the extent allowed by the JMM.

As you surmise, the danger here is that thread B will see a non-null
reference to an incompletely constructed resource.


PS - The JMM FAQ could use another update on this topic:


On Sat, May 2, 2009 at 12:21 PM, Carol Saah wrote:
>> Hello,
>> I understand from Brian Goetz that we should NOT use
>> Double-Checked-Locking.
>> However, I am trying to understand exactly what can happen in the
>> incorrectly synchronized code that appears in the article, "Double-checked
>> locking: Clever, but broken."  I realize that
>> http://www.javaworld.com/jw-02-2001/jw-0209-double.html?page=4 is very
>> old
>> and that some comments may be old; however, the reordering issue is not
>> old.
>> The code in question is:
>> class SomeClass {
>>  private Resource resource = null;
>>  public Resource getResource() {
>>    if (resource == null) {
>>      synchronized (this) {
>>        if (resource == null)
>>          resource = new Resource();
>>      }
>>    }
>>    return resource;
>>  }
>> }
>> On page 4 of the article, "So what's broken about DCL?", I would like to
>> get
>> a more precise description of the 1st scenario discussed in that section.
>> This is my understanding with questions.
>> The reordering discussed in the scenario happens in dynamic compilation
>> and
>> would seem to happen once and apply to all threads for a class, correct?
>> And, does dynamic compilation happen just before JIT?
>> In the example, the compiler chooses to reorder the instructions of
>> getResource() to: allocate memory, assign reference to resource, call
>> constructor.
>> But, in a thread, the as-if-sequential semantics hold, so do those
>> instructions happen AFTER the thread has done all of its work in the
>> "local
>> memory."
>> And, do the instructions apply to main memory only?
>> Here is the scenario in the example.
>> Thread A has invoked getResource() on a someClass object.
>> Thread A finds that resource is null and so Thread A invokes the
>> constructor
>> for Resource and sets the resource.
>> Thread A still has not exited the synchronized block so no writes have
>> been
>> made to main memory.
>> Thread A's state is in its "local memory" on the processor or cache in
>> which
>> it is running.
>> But, before Thread B invokes, getResource(), these "reordered
>> instructions"
>> happen for Thread A:  allocate memory, assign reference to resource
>> Now, Thread B invokes getResource().
>> Thread B finds the reference to resource that the "reordered" instructions
>> from Thread A put into main memory.
>> But, in the meantime, the processor executing the instructions for Thread
>> A
>> still has not caused the constructor to execute in main memory so main
>> memory has a reference but nothing in it.
>> So, is this why Thread B is partially constructed?
>> Thanks.
>> Carol Saah
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20090502/6695c706/attachment-0001.html>

More information about the Concurrency-interest mailing list