[concurrency-interest] Double Checked Locking in OpenJDK

Zhong Yu zhong.j.yu at gmail.com
Wed Aug 15 19:47:25 EDT 2012


On Wed, Aug 15, 2012 at 6:21 PM, David Holmes <davidcholmes at aapt.net.au> wrote:
> Ruslan Cheremin writes:
>>
>> > 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.
>
> You have to be able to establish the necessary happens-before relationships
> between the end of construction, publication and use.
>
> If thread-safe means you've created a "monitor" where only one method
> invocation can proceed at a time and all methods are synchronized, then
> synchronized in the constructor will construction happens-before use, and
> the publication mechanism is not relevant.
>
> If all your fields are final or volatile then you also have no issue with
> publication.

Example why volatile does not guarantee that.

    class Foo
        volatile x = 42;

    // thread 1
    foo = new Foo();  // unsafe pub

    // thread 2
    r = foo;
    if(r!=null)
        print(r.x);  // may print "0"

> Otherwise you have a bit more work to do. Relying on safe-publication to
> introduce the happens-before ordering allows you to use simpler, more
> natural, and likely more performant code in your thread-safe class.
>
> David
> -----
>
>
>> 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


More information about the Concurrency-interest mailing list