[concurrency-interest] synchronized constructors

Roland Kuhn rk at rkuhn.info
Mon Jan 16 14:04:03 EST 2012


On 16 jan 2012, at 17:53, Ruslan Cheremin <cheremin at gmail.com> wrote:

> JSL 17.5.3, http://java.sun.com/docs/books/jls/third_edition/html/memory.html#60903
> 
> "In some cases, such as deserialization, the system will need to
> change the final fields of an object after construction. Final fields
> can be changed via reflection and other implementation dependent
> means. The only pattern in which this has reasonable semantics is one
> in which an object is constructed and then the final fields of the
> object are updated. The object should not be made visible to other
> threads, nor should the final fields be read, until all updates to the
> final fields of the object are complete. Freezes of a final field
> occur both at the end of the constructor in which the final field is
> set, and immediately after each modification of a final field via
> reflection or other special mechanism."
> 
> So it you do not publish reference,

This is precisely the weak spot: if publication happens by data race, the JMM does not guarantee anything (as I was told in this thread). It might work in practice on current processors because the memory barriers supported are coarse grained, but that may change in the future, breaking this code. 

> and do not read field which will
> be modified -- you'll have "freeze" action after reflection-based
> update of final field, which is the same as in the end of constructor.
> It will look like you have long-long constructor, which finished just
> here.
> 
> Just read carefully subsequent warnings in JLS, about setting final
> field to compile time constant, which can be inlined by compiler.  It
> seems like you should set initial f-field value to something, passed
> from constructor -- to prevent inlining.
> 
Yes, good idea, but see above. 

Regards,

Roland

> 16 января 2012 г. 20:42 пользователь √iktor Ҡlang
> <viktor.klang at gmail.com> написал:
>> 
>> 
>> On Mon, Jan 16, 2012 at 5:33 PM, Ruslan Cheremin <cheremin at gmail.com> wrote:
>>> 
>>> 2011/12/17 Roland Kuhn <rk at rkuhn.info>:
>>>> You might ask, why have a non-final field without proper
>>>> synchronization, so
>>>> let me add that the background to this question is that in my case the
>>>> construction of the object needs to proceed in two phases because of
>>>> other
>>>> inter-dependencies, which requires certain fields to be written to after
>>>> the
>>>> constructor has finished; they will be written to only exactly once, and
>>>> this happens before “untrusted” client code obtains the reference (in
>>>> program order).
>>> 
>>> May be it's too late for this -- but you can still use final fields,
>>> but update them via reflection. If you do not publish object reference
>>> _before_ all reflection-based modifications finished -- you still have
>>> all final fields guarantee. From you description it seems like it is
>>> your case.
>>> 
>> 
>> That's interesting, can you point me to the spec?
>> 
>> Cheers,
>>>> 
>> 
>>> 
>>> 
>>>> Thanks in advance,
>>>> 
>>>> Roland
>>>> 
>>>> On Dec 16, 2011, at 22:49 , Boehm, Hans wrote:
>>>> 
>>>> Just to be clear: Safe publication for final fields requires that you do
>>>> not
>>>> make a pointer to the object available to other threads (publish it)
>>>> before
>>>> the constructor finishes.  “Safe publication” as used below is a
>>>> slightly
>>>> stronger property; you also should not communicate the pointer
>>>> post-construction to another thread via a data race.  Avoiding them both
>>>> is
>>>> great advice, but the second one may be difficult to avoid if you need
>>>> to
>>>> give a reference to your object to code you don’t trust.  Malicious code
>>>> could always pass the object to a third thread through a race, hoping
>>>> that
>>>> the third thread, which has no happens-before relationship to the other
>>>> two,
>>>> would find your object in an inconsistent state.  My intuition is that
>>>> this
>>>> is a rare case, but one that does occur.  When it does occur, the odds
>>>> of an
>>>> actual security hole are probably small, but so are the odds of proving
>>>> security properties without addressing the issue.
>>>> 
>>>> Hans
>>>> 
>>>> From: concurrency-interest-bounces at cs.oswego.edu
>>>> [mailto:concurrency-interest-bounces at cs.oswego.edu] On Behalf Of Yuval
>>>> Shavit
>>>> Sent: Friday, December 16, 2011 11:59 AM
>>>> To: Zhong Yu
>>>> Cc: concurrency-interest at cs.oswego.edu
>>>> Subject: Re: [concurrency-interest] synchronized constructors
>>>> 
>>>> On Fri, Dec 16, 2011 at 2:10 PM, Zhong Yu <zhong.j.yu at gmail.com> wrote:
>>>> 
>>>> On Fri, Dec 16, 2011 at 8:38 AM, Yuval Shavit <yshavit at akiban.com>
>>>> wrote:
>>>>> Several people have made the claim that you could see partially
>>>>> initialized
>>>>> state even if the constructor were synchronized, and I don't see how
>>>>> this
>>>>> could be. Yes, you could assign MyPoint myUnsafeRef before MyPoint()
>>>>> finishes -- but if you ever tried to *use* myUnsafeRef, you would run
>>>>> into
>>>>> a
>>>>> synchronized block which would then ensure that the constructor
>>>>> happened-before whatever method you're writing. Seems to me you should
>>>>> see
>>>>> the fully-thread-safe, not-partially-initialized object at that point.
>>>> 
>>>> 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.
>>>> 
>>>> Ah yes, I hadn't thought of that.
>>>> 
>>>> So now, in order to have my class be over-achievingly thread safe, I
>>>> need to
>>>> replace my synchronized methods with a latch that waits for construction
>>>> to
>>>> finish and *then* a synchronized (this) {...}. But I probably decide
>>>> that
>>>> this is really going far out of my way to support a bad usage pattern,
>>>> so I
>>>> throw up my arms and say "you'll see either totally blank or
>>>> post-initialization state, but not partial initialization."  But that
>>>> means
>>>> I have to guard against uninitialized state in each method, so I
>>>> probably
>>>> throw up my arms again and say "just publish the darn object safely!"
>>>>  And
>>>> then the JLS people come to me and say, "well if that's your
>>>> requirement,
>>>> why do you want a synchronized constructor?"  And suddenly the whole
>>>> thing
>>>> makes sense.
>>>> 
>>>> This has been an interesting discussion for me! Thanks everyone. :)
>>>> 
>>>> -Yuval
>>>> _______________________________________________
>>>> Concurrency-interest mailing list
>>>> Concurrency-interest at cs.oswego.edu
>>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>>> 
>>>> 
>>>> --
>>>> [scala-debate on 2009/10/2]
>>>> Viktor Klang: When will the days of numerical overflow be gone?
>>>> Ricky Clarkson: One second after 03:14:07 UTC on Tuesday, 19 January
>>>> 2038
>>>> 
>>>> 
>>>> _______________________________________________
>>>> 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
>> 
>> 
>> 
>> 
>> --
>> Viktor Klang
>> 
>> Akka Tech Lead
>> Typesafe - The software stack for applications that scale
>> 
>> Twitter: @viktorklang
>> 



More information about the Concurrency-interest mailing list