[concurrency-interest] synchronized constructors

Vitaly Davidovich vitalyd at gmail.com
Thu Dec 15 17:58:42 EST 2011


That's not what I thought was being asked - it sounds like the question was
whether another CPU can observe the reordering of store to a and store to b
without a publication in between.  Of course if you publish in between
anything goes.
On Dec 15, 2011 5:52 PM, "David Holmes" <davidcholmes at aapt.net.au> wrote:

> **
> I'm not aware of any "data dependency" rules in the JMM.
>
> Yuval's example could be reordered to:
>
> a = 1;
> publish ref
> b = a;
>
> allowing another thread to see b==0.
>
> The "Final Field" section of the JMM cookbook end with this caution:
>
> "These rules imply that reliable use of final fields by Java programmers
> requires that the load of a shared reference to an object with a final
> field itself be synchronized, volatile, or final, or derived from such a
> load, thus ultimately ordering the initializing stores in constructors with
> subsequent uses outside constructors. "
>
> David
>
> -----Original Message-----
> *From:* Vitaly Davidovich [mailto:vitalyd at gmail.com]
> *Sent:* Friday, 16 December 2011 8:47 AM
> *To:* Yuval Shavit
> *Cc:* dholmes at ieee.org; concurrency-interest
> *Subject:* Re: [concurrency-interest] synchronized constructors
>
> No that would violate data dependency.
> On Dec 15, 2011 5:38 PM, "Yuval Shavit" <yshavit at akiban.com> wrote:
>
>> Wouldn't the final field only establish that reads to *that field* see at
>> least the state it was in at end of construction? That is, if you had two
>> fields:
>>
>> final int a;
>> int b;
>>
>> And your constructor were:
>>     a = 1;
>>     b = a;
>>
>> Then, in the absence of correct publication, couldn't another thread
>> still see a = 1, b = 0?
>>
>> On Thu, Dec 15, 2011 at 5:25 PM, David Holmes <davidcholmes at aapt.net.au>wrote:
>>
>>> **
>>> final field yes. Write to a volatile no.
>>>
>>> The volatile only works if the other thread reads the volatile and sees
>>> the written value.
>>>
>>> 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:* Friday, 16 December 2011 8:20 AM
>>> *To:* Yuval Shavit
>>> *Cc:* concurrency-interest
>>> *Subject:* Re: [concurrency-interest] synchronized constructors
>>>
>>>  > it seems to me that if all of the constructor had been wrapped in a
>>> synchronized (this) {...}
>>>
>>> One could also add a final field in the class or have the constructor
>>> write to a volatile at the end of the method.  Both of these would add a
>>> happens-before.
>>>
>>> Nathan Reynolds<http://psr.us.oracle.com/wiki/index.php/User:Nathan_Reynolds>| Consulting Member of Technical Staff |
>>> 602.333.9091
>>> Oracle PSR Engineering <http://psr.us.oracle.com/> | Server Technology
>>>
>>> On 12/15/2011 2:59 PM, Yuval Shavit wrote:
>>>
>>> Oh, I totally understand why it's a bad idea -- and I was about to reply
>>> to your reply to Ruslan, saying that my version was basically a poor man's
>>> double-checked lock. It's actually not even a real DCL, because that
>>> pattern at least tries to ensure that only one thread will instantiate the
>>> object, whereas my code will happily create multiple instances, each living
>>> in its own place on some CPU's cache. The hypothetical author of that code
>>> might even say that's intentional, because he wants to shard or something.
>>> Like I said, I fully understand it's a bad pattern. On the other hand, it
>>> seems to me that if all of the constructor had been wrapped in a
>>> synchronized (this) {...}, this broken sharding/DCL would work: either you
>>> instantiate the object yourself (and thus see it fully instantiated) or
>>> you'll hit a synchronized(this) block on toString(), which will establish
>>> that the constructor's synchronized(this) happened-before toString's.
>>>
>>> On Thu, Dec 15, 2011 at 4:52 PM, Nathan Reynolds <
>>> nathan.reynolds at oracle.com> wrote:
>>>
>>>> This smells like double-checked locking.  Without a volatile or
>>>> synchronized, then this is definitely not going to work correctly and is
>>>> not thread-safe.  Look up double-checked locking on the web to see why it
>>>> is not thread-safe.
>>>>
>>>>
>>>> Nathan Reynolds<http://psr.us.oracle.com/wiki/index.php/User:Nathan_Reynolds>| Consulting Member of Technical Staff |
>>>> 602.333.9091
>>>> Oracle PSR Engineering <http://psr.us.oracle.com/> | Server Technology
>>>>
>>>>  On 12/15/2011 2:43 PM, Yuval Shavit wrote:
>>>>
>>>> So is the assumption that safe initial publication to other threads is
>>>> always required, and thread safety guarantees only kick in once that's been
>>>> done?
>>>>
>>>> I could imagine someone assigning their MyPoint to a non-volatile
>>>> static and creating a new instance if that static is null:
>>>>
>>>> public static MyPoint myPoint;
>>>>
>>>> MyPoint getAnyOldPoint() {
>>>>     if (myPoint == null)
>>>>         myPoint = new MyPoint();
>>>>     return myPoint;
>>>> }
>>>>
>>>> The person who writes that code (not me! :)  ) says, "I don't care
>>>> which MyPoint I get -- I don't care if it's the same one another thread
>>>> sees or not. All I care is that there is one, and that it's thread-safe.
>>>> And I got one (didn't have to instantiate it in this method), but it wasn't
>>>> thread safe: I saw "(0,-1)" even though no thread could have possibly set
>>>> such a state. I must have seen the initial state of a MyPoint, but it
>>>> wasn't thread safe."
>>>>
>>>> Now, I would love to tell them "sure it's thread safe, you're just
>>>> doing stupid things." But would they be wrong in telling me that no, my
>>>> class is only *partially* thread safe?
>>>>
>>>> Yuval
>>>>
>>>>
>>>>  On Thu, Dec 15, 2011 at 4:30 PM, Nathan Reynolds <
>>>> nathan.reynolds at oracle.com> wrote:
>>>>
>>>>> How is the MyPoint instance going to become shared with another
>>>>> thread?  The thread calling the constructor has to execute some sort of
>>>>> synchronization to share the reference to the MyPoint instance.  The
>>>>> synchronization will cause a happens-before edge to be created.  For
>>>>> example, this code assigns a volatile field.  Writing to the volatile will
>>>>> ensure the proper values of x and y will be visible.
>>>>>
>>>>> public volatile MyPoint point = new MyPoint();
>>>>>
>>>>> Nathan Reynolds<http://psr.us.oracle.com/wiki/index.php/User:Nathan_Reynolds>| Consulting Member of Technical Staff |
>>>>> 602.333.9091
>>>>> Oracle PSR Engineering <http://psr.us.oracle.com/> | Server Technology
>>>>>
>>>>> On 12/15/2011 2:10 PM, Yuval Shavit wrote:
>>>>>
>>>>>  Hi all,
>>>>>
>>>>> This came up a few days ago on stackoverflow.com -- I forget the
>>>>> exact post, but someone referenced the JLS section concerning why
>>>>> constructors can't be synchronized:
>>>>>
>>>>> There is no practical need for a constructor to be synchronized,
>>>>>> because it would lock the object under construction, which is normally not
>>>>>> made available to other threads until all constructors for the object have
>>>>>> completed their work.
>>>>>
>>>>>
>>>>> If synchronization were only about mutual exclusion, this would make
>>>>> sense; but it also has memory visibility guarantees. For instance, say I
>>>>> have this really simple class:
>>>>>
>>>>>      public class MyPoint {
>>>>>         private int x;
>>>>>         private int y;
>>>>>
>>>>>         public MyPoint() {
>>>>>             x = -1; // init to (-1,-1) for some reason
>>>>>             y = -1;
>>>>>         }
>>>>>
>>>>>         public synchronized void setX(int x, int y) {
>>>>>             this.x = x;
>>>>>             this.y = y;
>>>>>         }
>>>>>
>>>>>         @Override
>>>>>         public synchronized String toString() {
>>>>>             return "(" + x + ", " + y + ")";
>>>>>         }
>>>>>     }
>>>>>
>>>>> There's a thread safety issue there, right? There was no
>>>>> synchronization during construction time, and thus no happens-before
>>>>> between ctor ending and toString() starting, so with reordering etc, you
>>>>> could observe the initial state as "(0, 0)", "(-1, 0)", "(-1, -1)" or "(-1,
>>>>> 0)".  You could get around this by calling setX from the constructor, but
>>>>> if setX is non-final, that has its own issues. You could also put the x and
>>>>> y initialization within a synchronized (this) { ... } -- but at that point,
>>>>> why not just allow the constructor to be synchronized?
>>>>>
>>>>> Thanks,
>>>>> Yuval
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> Concurrency-interest mailing listConcurrency-interest at cs.oswego.eduhttp://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
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20111215/0ee2b194/attachment-0001.html>


More information about the Concurrency-interest mailing list