[concurrency-interest] synchronized constructors

David Holmes davidcholmes at aapt.net.au
Sat Dec 17 18:40:26 EST 2011


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
>
>




More information about the Concurrency-interest mailing list