[concurrency-interest] synchronized constructors

Roland Kuhn rk at rkuhn.info
Fri Dec 16 04:48:46 EST 2011


As I was recently made aware: the rules for write reordering are not as weak as you think.

http://java.sun.com/docs/books/jvms/second_edition/html/Threads.doc.html#24432

Section 8.8 of the JVM spec requires that a write cannot be moved earlier across a “lock” operation. This means that a synchronized {} in the constructor solves the issue.

Regards,

Roland

On Dec 16, 2011, at 08:58 , Zhong Yu wrote:

> I'm totally sympathetic to this design goal - if an object claims to
> be thread safe, it should survive unsafe publication without problems.
> I believe all java.util.concurrent classes have this property.
> 
> However, `synchronized` constructor cannot help to reach that goal.
> 
>    foo = new Foo();
> 
> is roughly equivalent to
> 
>    [A]    tmp = allocate memory space for sizeof(Foo)
>    [B]    zero the space. (this may occur before [A])
>    [1]    tmp.Foo(); // as if the constructor is an instance method
>    [2]    foo = tmp;
> 
> [2] can be reordered before [1], so other threads may observe
> blank/partial state through `foo` reference. This reordering is
> allowed even if `Foo()` is synchronized.
> 
> This problem affects some "thread safe" classes like java.util.Vector.
> If a Vector object is unsafely published, program can crash
> unexpectedly. I bet that's a huge surprise to most Java programmers.
> 
> But I don't think the "unenlightened mass" are to blame. We have this
> strong intuition that an object comes to existence only after
> construction. Nobody outside of construction should observe a
> partially constructed object (unless `this` is leaked during
> construction).
> 
> If JMM has this simple "whole-birth" guarantee, many man-hours of
> anguish will be saved. You can innocently do a double checked locking,
> and nobody is going to yell at your naivety.
> 
> Unfortunately JMM doesn't have this guarantee. Allegedly such
> guarantee carries a performance penalty. The only work around is
> through `final` fields. Neither `synchronized` nor `volatile` is
> useful for this purpose (many people are mistaken on this point; it is
> due to their whole-birth intuition, subconsciously adding a
> synchronization order from end of constructor to begin of instance
> methods)
> 
> We are encouraged to use `final` fields whenever we can. One crucial
> reason is for the memory effect guarantee. However, using `final`
> fields will incur the same performance penalty of whole-birth
> guarantee. We have a great contradiction here. Either `final` is not
> cheap, so we should avoid `final` fields if we can; or `final` is
> cheap, so whole-birth guarantee can be established cheaply, yielding
> `final` unnecessary.
> 
> JMM does guarantee that [2] cannot be reordered before [B], otherwise
> other threads can observe garbage state. Let's call this the "blank"
> guarantee. It's also a mystery to me why whole-birth guarantee can be
> fundamentally more expensive than blank guarantee.
> 
> Note that not everybody promotes the use of `final` though. We can
> sense how reserved David Holmes is through his words: " #Sometime# a
> class needs to add #some# protection against unsafe-publication that
> might violate #important# semantic guarantees of the object"
> 
> (We had a similar discussion in a September thread titled "Interesting
> anti-pattern with volatile"; however I cannot find it on the mailing
> list archive, so no link.)
> 
> Zhong Yu
> 
> P.S. a "fix" to Vector's vulnerability to unsafe publication
> 
> class Vector
> 
>    final Params ctorParams;
> 
>    Vector(params)
>        ctorParams = new Params(params);
> 
>    boolean initDone;
> 
>    void ensureInit()
>        if(!initDone)
>            initialize this with ctorParams ...
>            initDone = true;
> 
>    synchronized
>    public Foo anyOtherMethod(Bar)
>        ensureInit();
>        actual work...
> 
> Of course, this solution sucks. The role of constructor is severely weakened.
> _______________________________________________
> 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




More information about the Concurrency-interest mailing list