[concurrency-interest] synchronized constructors

Roland Kuhn rk at rkuhn.info
Sun Dec 18 10:09:33 EST 2011


Yes, inspired by the JSR-133 cookbook I was alluding to roach motel semantics: the synchronized is just there to ensure that the volatile write has happened before the possibly non-volatile write of the newly constructed object’s reference to a possibly shared location is actually performed. This would mean that nobody can obtain a reference before initialization is done. And then I would like to arrive at the conclusion that the volatile read of “x” from a different thread must synchronize-with the initial write.

Does this work?

Roland

On Dec 18, 2011, at 00:40 , David Holmes wrote:

> Roland,
> 
> An empty synchronized block in a constructor, when there are no other
> synchronized regions of code, gains you nothing under the JMM as there are
> no happens-before edges established. Are you
> relying on the implementation of synchronized to issue specific memory
> barriers here?
> 
> David
> 
>> -----Original Message-----
>> From: Roland Kuhn [mailto:rk at rkuhn.info]
>> Sent: Sunday, 18 December 2011 1:46 AM
>> To: dholmes at ieee.org
>> Cc: Zhong Yu; concurrency-interest at cs.oswego.edu
>> Subject: Re: [concurrency-interest] synchronized constructors
>> 
>> 
>> Thank you, David and Hans, for clarifying these semantics. The
>> OP’s question has been answered, and I think I can also derive an
>> answer for my question. I’ll try to wrap it up below, please
>> correct or confirm:
>> 
>> class IAmSafe {
>>  private volatile int x;
>>  IAmSafe() {
>>    x = 5;
>>    synchronized(this) {}
>>  }
>>  public int getX() {
>>    return x;
>>  }
>> }
>> 
>> Assuming that the java.lang.Object constructor is well-behaved,
>> it should be impossible under any circumstances (barring
>> reflective modification) that a call to getX() returns anything
>> but 5, right?
>> 
>> If this is true, then the cheapest solution to my multi-stage
>> construction problem—where I completely control the program flow
>> up to the point where I consider the object initialization
>> finished—on x86 processors looks like this:
>> 
>> class ComplexDeps {
>>  final int someValue;
>>  ComplexDeps(int someValue) {
>>    this.someValue = someValue;
>>  }
>>  // stage 2
>>  private volatile OtherThing thing;
>>  public void init(OtherThing thing) {
>>    this.thing = thing;
>>    synchronized {}
>>  }
>>  // other stuff which reads someValue & “thing”, never writes to
>> “thing” and runs only after init() in program order
>> }
>> 
>> IIUC, there will be a (half-way) expensive fence-like instruction
>> emitted at the end of init(), but apart from that all read
>> accesses after construction should be cheap. Any nobody will ever
>> see “thing” uninitialized.
>> 
>> Regards,
>> 
>> Roland
>> 
>> On Dec 17, 2011, at 09:57 , David Holmes wrote:
>> 
>>> Correction ...
>>> I wrote:
>>>> Zhong Yu writes:
>>>>> Suppose constructor java.util.Vector() is synchronized
>>>>> 
>>>>>   static Vector v;
>>>>> 
>>>>>   // thread 1
>>>>>   v = new Vector();
>>>>> 
>>>>>   // thread 2
>>>>>   Vector r = v;
>>>>>   if(r!=null)
>>>>>     r.add(x);
>>>>> 
>>>>> The last line can throw exception, because thread 2 can observe the
>>>>> blank state of the object
>>>> 
>>>> No it can not.
>>>> Completion of the constructor happens-before the reference is
>> published.
>>> 
>>> Delete this sentence. It's wrong but not relevant to the argument.
>>> 
>>> David
>>> -----
>>> 
>>> 
>>>> The acquiring of the monitor in add() can only happen when the
>>>> monitor is released by the constructor. The release of the
>>>> monitor in thread
>>>> 1 happens-before the acquire of the monitor by thread 2. All the
>>>> constructor
>>>> actions happen-before the release of the monitor.
>>>> 
>>>> The publishing of the Vector can not be moved prior to the
>> acquisition of
>>>> the monitor in the constructor ("roach motel semantics").
>>>> 
>>>> David
>>>> -----
>>>> 
>>>> 
>>>>> , yet Vector.add() presumes a> post-construction state.
>>>> 
>>>>> Zhong Yu
>>>>> 
>>>>> On Fri, Dec 16, 2011 at 7:52 PM, David Holmes
>>>>> <davidcholmes at aapt.net.au> wrote:
>>>>>> Zhong Yu writes:
>>>>>>> If the reference is unsafely published, another thread can get the
>>>>>>> reference early; it then calls an instance method which may
>>>> obtain the
>>>>>>> lock before the creation thread can obtain the lock for the
>>>>>>> constructor. Therefore the other thread can observe the blank state.
>>>>>>> As Ruslan corrected me, no partial state can be observed though.
>>>>>> 
>>>>>> The only way this can happen, if you synchronize the whole
>>>>> constructor body,
>>>>>> is if a super class constructor does the unsafe publishing. But
>>>>> in that case
>>>>>> there is no such thing as safe-publishing because the object
>>>> can escape
>>>>>> before the subclass constructor does any initialization.
>>>>>> 
>>>>>> To summarize a long and garbled thread. If the constructor body is
>>>>>> synchronized, there is no accessible state and all methods are
>>>>> synchronized,
>>>>>> then no external user of the class can publish a reference in a
>>>>> way that is
>>>>>> unsafe. If the constructor does the publishing within the
>> synchronized
>>>>>> block, it is still safe. Only if the superclass does it can it
>>>>> possibly be
>>>>>> unsafe.
>>>>>> 
>>>>>> Also to address an other point: lock elision is allowed (eg
>>>> using escape
>>>>>> analysis) but the memory synchronization effects must remain
>>>>> (you can lose
>>>>>> enforced mutual exclusion [as you don't need it], but not
>>>> happens-before
>>>>>> edges).
>>>>>> 
>>>>>> Constructors can't be synchronized simply because back in 1995 no one
>>>>>> realized there could be a need for it. It can be mostly
>>>> worked around by
>>>>>> using a synchronized block. But you can't synchronize the
>>>>> invocation of the
>>>>>> super constructor.
>>>>>> 
>>>>>> End of story :)
>>>>>> 
>>>>>> Cheers,
>>>>>> David
>>>>>> 
>>>>> 
>>>> 
>>>> _______________________________________________
>>>> Concurrency-interest mailing list
>>>> Concurrency-interest at cs.oswego.edu
>>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>>> 
>>> 
>>> _______________________________________________
>>> Concurrency-interest mailing list
>>> Concurrency-interest at cs.oswego.edu
>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>> 
>> --
>> Simplicity and elegance are unpopular because they require hard
>> work and discipline to achieve and education to be appreciated.
>>  -- Dijkstra
>> 
>> 
> 

--
I'm a physicist: I have a basic working knowledge of the universe and everything it contains!
    - Sheldon Cooper (The Big Bang Theory)




More information about the Concurrency-interest mailing list