[concurrency-interest] Double Checked Locking in OpenJDK

David Holmes davidcholmes at aapt.net.au
Wed Aug 15 19:44:08 EDT 2012


Zhong Yu writes:
>
> Any use case for unsafe publication of a mutable thread-safe object?
>
> If a use case does exist, there is a way to do it without
> synchronizing constructor:
>
>     local_var = new Vector();  // not synchronized
>     local_var.size();  // call a synchronized method
>     shared_var = local_var;  // unsafe publication
>
> therefore synchronized constructor still isn't necessary.

The above is turning unsafe publication into safe-publication.

As I said in other email the whole issue here is to ensure that construction
happens-before use. In the sharing case publication has to occur prior to
use. That means you either tackle the problem directly, by ensuring
construction happens-before use (ie with synchronized constructor on fully
synchronized object). Or you establish that construction happens-before
publication and publication happens-before use aka you use safe-publication
mechanisms.

David
------


> Though, aesthetically, one might prefer to do synchronization in
> constructors the same way it's done in instance methods, if the
> overhead isn't a concern.
>
> Zhong Yu
>
> On Wed, Aug 15, 2012 at 2:56 PM, Ruslan Cheremin
> <cheremin at gmail.com> wrote:
> > Yes, it was an interesting discussion, and as result object with
> > synchronized methods and constructor can be published unsafe (i.e.
> > other thread can obtain reference to partially initialized object),
> > but this patrially initialized state can't be observed, since all
> > access going via sync-ed methods, which will block until
> > initialization finish.
> >
> > So, staying away from the unsual and so strange and even ugly notation
> > of locking in constructor, making object self-safe-publishing is not
> > anything more complex, then making thread-safe method. Am I missed
> > something?
> >
> > 2012/8/15 Zhong Yu <zhong.j.yu at gmail.com>:
> >> I thought the conclusion of that thread is that synchronizing
> >> constructor has the desired merit - if all constructors and methods
> >> are synchronized, a non-creating thread won't observe the zero/partial
> >> state of the object, even if the object reference is published
> >> unsafely.
> >>
> >> (One guy, who shall remain nameless, muddied the water with some
> >> mistaken statements of weaker memory guarantee. He has been corrected)
> >>
> >> Zhong Yu
> >>
> >> On Wed, Aug 15, 2012 at 11:58 AM, Yuval Shavit
> <yshavit at akiban.com> wrote:
> >>> There was a discussion here a few months ago about synchronizing
> >>> constructors -- I had asked why it's not allowed, and the
> discussion hit on
> >>> some of the similar points brought up in this thread.
> >>>
> >>> But to your point specifically, synchronizing a constructor (via
> >>> "synchronized(this) {...}" surrounding its body) still
> doesn't give you full
> >>> thread safety (even assuming immutability after the constructor -- but
> >>> without final fields). It ensures that a thread can observe the object
> >>> either fully constructed *or* with all its fields having their default
> >>> values. In other words, even if your constructor is
> synchronized on the same
> >>> object your getter is, a thread could observe a field as it
> was before the
> >>> constructor was invoked.
> >>>
> >>> http://markmail.org/message/mav53xzo4bqu7udw
> >>>
> >>>
> >>> On Wed, Aug 15, 2012 at 12:49 PM, Ruslan Cheremin <cheremin at gmail.com>
> >>> wrote:
> >>>>
> >>>> > The reason to keep them distinct is because in general the
> mechanisms
> >>>> > for
> >>>> > safe publication are external to the class, while those for
> >>>> > thread-safety
> >>>> > are internal. It is only an edge case where use of
> synchronized in a
> >>>> > constructor can achieve safe-publication.
> >>>>
> >>>> Well, actually I do not understand your point. If I use some kind of
> >>>> synchronization to make methods of my object thread-safe -- can't I
> >>>> also apply same thing to constructor? For me, it makes the thing only
> >>>> clearer. Object can be thread-safe -- and it is totally thread safe.
> >>>> Object can require external synchronization for correct multithreaded
> >>>> use -- and it requires the sync for publishing and for usage also.
> >>>>
> >>>> From my point of view, the distinction you talking about is more
> >>>> historically reasoned. "Sync method if you want it to be thread-safe"
> >>>> is commonly learned mantra, but "take care of initialization also" is
> >>>> not so common. More information about it, more education, more
> >>>> different code samples with outlined "here is the dragons"
> will change
> >>>> the situation, I sure, it just have to be highlighted more often.
> >>>>
> >>>>
> >>>> > People have to recognize that sharing an object requires
> shared mutable
> >>>> > state, and the number one tenet of concurrent programming
> is that access
> >>>> > to
> >>>> > shared mutable state has to be synchronized (in a general sense not
> >>>> > specifically use of 'synchronized' keyword).
> >>>> >
> >>>> > Making every object safely publishable could be done, but
> for 99% of
> >>>> > objects
> >>>> > it would be a waste of effort. Programs without data races
> don't have
> >>>> > issues
> >>>> > with unsafe publication.
> >>>> >
> >>>> > David
> >>>> >
> >>>> > -----Original Message-----
> >>>> > From: concurrency-interest-bounces at cs.oswego.edu
> >>>> > [mailto:concurrency-interest-bounces at cs.oswego.edu]On
> Behalf Of Nathan
> >>>> > Reynolds
> >>>> > Sent: Wednesday, 15 August 2012 4:59 AM
> >>>> > To: concurrency-interest at cs.oswego.edu
> >>>> > Subject: Re: [concurrency-interest] Double Checked Locking
> in OpenJDK
> >>>> >
> >>>> > We seem to be splitting two notions (i.e thread-safe and safe
> >>>> > publication)
> >>>> > when they should be combined in a sense.  Typically, when we say
> >>>> > thread-safe
> >>>> > we talk about the operations performed on the object after it was
> >>>> > constructed (and its contents are globally visible).
> However, we need
> >>>> > to
> >>>> > consider that executing the constructor is modifying the
> state of the
> >>>> > object.  It requires the same mechanisms that the rest of
> the class uses
> >>>> > to
> >>>> > ensure thread-safety.  Even though, there is only 1 thread
> executing the
> >>>> > constructor, a proper releasing of a lock or some other
> happens-before
> >>>> > construct is required to ensure that the memory updates by
> the thread
> >>>> > are
> >>>> > made globally visible before the object is accessed by
> another thread.
> >>>> > This
> >>>> > is what we are calling safe publication.  So, safe publication is a
> >>>> > subset
> >>>> > of thread-safety except it is limited to what happens after the
> >>>> > constructor
> >>>> > is called and before the object is used by multiple threads.
> >>>> >
> >>>> > A beautifully-written class can be thread-safe with
> respect to calling
> >>>> > its
> >>>> > member methods but not thread-safe with respect to calling its
> >>>> > constructor.
> >>>> > It is this latter case that many stumble upon because they
> think that
> >>>> > constructors are inherently thread-safe because they are executed
> >>>> > single-threadedly.  What they fail to realize is that the
> execution of a
> >>>> > constructor can overlap with the execution of other code
> from the view
> >>>> > point
> >>>> > of what is happening in memory.  This same problem applies
> to more rare
> >>>> > case
> >>>> > of regular methods which can be proven to execute in a
> single thread but
> >>>> > don't use synchronization before multiple threads start
> accessing the
> >>>> > shared
> >>>> > data.
> >>>> >
> >>>> > Nathan Reynolds | Consulting Member of Technical Staff |
> 602.333.9091
> >>>> > Oracle PSR Engineering | Server Technology
> >>>> > On 8/13/2012 4:08 PM, David Holmes wrote:
> >>>> >
> >>>> > Ruslan Cheremin writes:
> >>>> >
> >>>> > For me it is confusing: java has only one way to have
> really immutable
> >>>> > object, and this way also gives you a total thread safety even for
> >>>> > data race based publication. But then docs refer object as
> "immutable
> >>>> > and thread-safe" -- we still can't assume it to be really
> thread-safe?
> >>>> >
> >>>> > It is better/simpler to isolate the notion of
> thread-safety and safe
> >>>> > publication. Thread-safety comes into play after you have
> safely shared
> >>>> > an
> >>>> > object. The means by which you safely share an object is
> orthogonal to
> >>>> > how
> >>>> > the object itself is made thread-safe.
> >>>> >
> >>>> > The means by which an object is shared has to involve
> shared mutable
> >>>> > state,
> >>>> > and use of shared mutable state always needs some form of
> >>>> > synchronization
> >>>> > (either implicit eg due to static initialization; or
> explicit by using
> >>>> > volatile or synchronized getter/setter methods).
> >>>> >
> >>>> > David
> >>>> > -----
> >>>> >
> >>>> > It's a pity, especially because true immutability gives us some
> >>>> > chances of performance optimization. As in this case -- we do not
> >>>> > really need .path to be volatile here, if we would assume
> Path to be
> >>>> > truly immutable. volatility here required only for ensuring safe
> >>>> > publishing.
> >>>> >
> >>>> > 2012/8/13 David Holmes <davidcholmes at aapt.net.au>:
> >>>> >
> >>>> > Ruslan Cheremin writes:>
> >>>> >
> >>>> > But is there a way to define "safe for data race publishing"? I as
> >>>> > far, as I remember, "immutable and thread-safe" is
> standard mantra in
> >>>> > JDK javadocs for totally safe objects. j.l.String has same
> mantra --
> >>>> > and it is safe for any way of publishing. Does you mean, I should
> >>>> > explicitly add "safe even for publishing via data race" in
> docs? But I
> >>>> > can't remember any such phrase in JDK docs.
> >>>> >
> >>>> > I don't recall anything in the JDK docs that mention being
> >>>> >
> >>>> > "totally safe"
> >>>> >
> >>>> > regardless of publication mechanism. Some classes, eg
> String, have been
> >>>> > defined such that they do have that property (for security
> reasons). In
> >>>> > general neither "thread-safe" nor "immutable" imply
> >>>> > safe-for-unsynchronized-publication.
> >>>> >
> >>>> > Java Concurrency In Practice (jcip.net) does define
> additional potential
> >>>> > annotations, where @Immutable would indeed capture the
> requirement of
> >>>> > safe-for-unsynchronized-publication.
> >>>> >
> >>>> > David
> >>>> > -----
> >>>> >
> >>>> > 2012/8/13 David Holmes <davidcholmes at aapt.net.au>:
> >>>> >
> >>>> > Ruslan Cheremin writes:
> >>>> >
> >>>> > Well, Path javadoc explicitly says "immutable and safe for
> >>>> > multithreaded use". Although it is not strictly defined in
> java what
> >>>> > exactly means "safe for multithreaded use" -- does it mean safe for
> >>>> > publishing via data race, among others? -- I suppose, it
> >>>> >
> >>>> > should be. Am
> >>>> >
> >>>> > I wrong here?
> >>>> >
> >>>> > "safe for multi-threaded use" does not generally imply that it
> >>>> >
> >>>> > is safe to
> >>>> >
> >>>> > publish instances without synchronization of some form.
> >>>> >
> >>>> > David
> >>>> > -----
> >>>> >
> >>>> > From other side, File.toPath javadoc explicitly says what "returned
> >>>> > instance must be the same for every invocation", so sync block is
> >>>> > required here for mutual exclusion on initialization phase. Without
> >>>> > this requirement it is also safe to live without sync block, afaik.
> >>>> >
> >>>> > 2012/8/13 David Holmes <davidcholmes at aapt.net.au>:
> >>>> >
> >>>> > Ruslan Cheremin writes:
> >>>> >
> >>>> > First of all, Path is immutable, so DCL is safe here even without
> >>>> > volatile. Volatile here is not required from my point of view.
> >>>> >
> >>>> > Without the volatile the Path implementation (Path is an
> >>>> >
> >>>> > interface) must be
> >>>> >
> >>>> > such that an instance of Path can be safely published without
> >>>> >
> >>>> > any additional
> >>>> >
> >>>> > forms of synchronization. Immutability does not in itself
> >>>> >
> >>>> > ensure that. You
> >>>> >
> >>>> > would have to examine the actual implementation class.
> >>>> >
> >>>> > David Holmes
> >>>> > ------------
> >>>> >
> >>>> > 2012/8/12 Dmitry Vyazelenko <vyazelenko at yahoo.com>:
> >>>> >
> >>>> > Hi Richard,
> >>>> >
> >>>> > The variable "filePath" is volatile, so the double-checked
> >>>> >
> >>>> > locking is correct in this case. It would have been a bug
> >>>> >
> >>>> > prior to Java 5.
> >>>> >
> >>>> > Best regards,
> >>>> >
> >>>> > Dmitry Vyazelenko
> >>>> >
> >>>> > On Aug 12, 2012, at 21:35 , Richard Warburton
> >>>> >
> >>>> > <richard.warburton at gmail.com> wrote:
> >>>> >
> >>>> > Hello,
> >>>> >
> >>>> > The current implementation of java.io.File::toPath [0]
> >>>> >
> >>>> > appears to be
> >>>> >
> >>>> > using the double checked locking pattern:
> >>>> >
> >>>> >     public Path toPath() {
> >>>> >         Path result = filePath;
> >>>> >         if (result == null) {
> >>>> >             synchronized (this) {
> >>>> >                 result = filePath;
> >>>> >                 if (result == null) {
> >>>> >                     result =
> >>>> >
> >>>> > FileSystems.getDefault().getPath(path);
> >>>> >
> >>>> >                     filePath = result;
> >>>> >                 }
> >>>> >             }
> >>>> >         }
> >>>> >         return result;
> >>>> >     }
> >>>> >
> >>>> > I was going to report the bug, but I'm a little
> >>>> >
> >>>> > uncertain of the
> >>>> >
> >>>> > interaction between the local variable 'result' and DCL
> >>>> >
> >>>> > since I've
> >>>> >
> >>>> > previously only seen the checking condition on the
> >>>> >
> >>>> > shared field
> >>>> >
> >>>> > itself.  Can someone here either confirm that its a bug or
> >>>> >
> >>>> > explain how
> >>>> >
> >>>> > the 'result' variable is fixing things?
> >>>> >
> >>>> > regards,
> >>>> >
> >>>> >  Richard
> >>>> >
> >>>> > [0] See the end of
> >>>> >
> >>>> > hg.openjdk.java.net/jdk8/jdk8/jdk/file/da8649489aff/src/share/clas
> >>>> >
> >>>> > ses/java/io/File.java
> >>>> >
> >>>> > _______________________________________________
> >>>> > 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
> >>>> >
> >>>> > _______________________________________________
> >>>> > 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
> >>>> >
> >>>> >
> >>>> >
> >>>> > _______________________________________________
> >>>> > 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
> >>>
> >>>
> >>>
> >>> _______________________________________________
> >>> Concurrency-interest mailing list
> >>> Concurrency-interest at cs.oswego.edu
> >>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> >>>
>



More information about the Concurrency-interest mailing list