[concurrency-interest] Double Checked Locking in OpenJDK

David Holmes davidcholmes at aapt.net.au
Wed Aug 15 20:09:49 EDT 2012


Zhong Yu writes:
>
> I'm not sure about the proper definition of safe/unsafe publication.

safe-publication simply means that you are guaranteed to see the values set
by the construction process. (Assuming  noone is concurrently changing
them).

> In any case, it's not easy to prove (on JMM rules) that the sync block
> in the creation thread is ordered before the sync blocks in other
> threads, so it's probably not worthwhile to contemplate such tricks.

Informally the asignment to shared_var can move inside the sync-block in
size, but can't move before size() (roach-motel rules). This is the same as
what can happen with a synchronized constructor. The mutual exclusion
(needed on all methods) ensures no other thread can access shared_var.m()
for some method m(), until after size() completes and releases the monitor
lock.

David

> On Wed, Aug 15, 2012 at 6:44 PM, David Holmes
> <davidcholmes at aapt.net.au> wrote:
> > 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