[concurrency-interest] do constructors ever involve threading under the covers?

Zhong Yu zhong.j.yu at gmail.com
Wed Oct 3 15:09:14 EDT 2012


I guess the spec is deliberately weakened, so that for example

    anInt = 1;
    anStr = new String(bytes);

no ordering constraint is imposed; the 1st write can be reordered
after the 2nd, passing the constructor with final field writes.

This seems unnecessarily sophisticated; too much for mortals.

On Wed, Oct 3, 2012 at 1:58 PM, Vitaly Davidovich <vitalyd at gmail.com> wrote:
> This depends on what exactly is the scope of a final field assignment, as
> Aleksey and I have discussed here.  If the mere presence of a final
> assignment in the ctor, irrespective of its order with other local
> assignments, means there's a StoreStore barrier placed right before shared
> ref assignment, then the whole body of the ctor is visible if the shared ref
> is, and thus no such reordering can occur.
>
> If StoreStore is placed right after the final assignment only, then it can.
>
> Sent from my phone
>
> On Oct 3, 2012 2:52 PM, "Zhong Yu" <zhong.j.yu at gmail.com> wrote:
>>
>> On Wed, Oct 3, 2012 at 1:44 PM, Vitaly Davidovich <vitalyd at gmail.com>
>> wrote:
>> > Final is stronger than volatile in terms of store operations inside ctor
>> > and
>> > subsequent assignment to the ref, which happens to enable the racy
>> > publication that still works; volatile wouldn't work.
>> >
>> > As for your example, it's not allowed.  In order for another thread to
>> > call
>> > verify(), they must have seen a non-null reference.  We also know that
>> > final
>> > assignment prevents reordering of ctor body with assignment to shared
>> > ref.
>>
>> If the compiler can prove that a write in ctor is to a location that
>> cannot be referenced through the final field, then the write can be
>> reordered, even after the write to shared ref.
>>
>> Such proof is probably difficult; unless the field is primitive.
>>
>> > I think I agree with Aleksey in that any final assignment in the ctor
>> > prevents the reordering.  Therefore, if thread sees non-null ref to call
>> > verify() on, it cannot see a == 0.
>> >
>> > Sent from my phone
>> >
>> > On Oct 3, 2012 1:51 PM, "Yuval Shavit" <yshavit at akiban.com> wrote:
>> >>
>> >> Is that true? I was under the impression that final only has memory
>> >> visibility implications for the final field itself, and anything gotten
>> >> from
>> >> it. So for instance:
>> >>
>> >> class Foo {
>> >>     int a;
>> >>     final boolean ctorDone;
>> >>
>> >>     Foo() {
>> >>         a = 1;
>> >>         ctorDone = true;
>> >>     }
>> >>
>> >>     void verify() {
>> >>         while (!ctorDone) { /* spin */ }
>> >>         assert a == 1 : a;
>> >>     }
>> >> }
>> >>
>> >> My understanding is that (assuming unsafe publication and all that) the
>> >> JMM is allowed to have a == 0 in Foo.verify, because the memory
>> >> visibility
>> >> only applies to ctorDone. If ctorDone were a volatile, then reading it
>> >> would
>> >> ensure a full HB edge, and you'd be guaranteed to see a == 1.
>> >>
>> >> On Wed, Oct 3, 2012 at 1:32 PM, Zhong Yu <zhong.j.yu at gmail.com> wrote:
>> >>>
>> >>> We may say `final` is stronger than `volatile`, it has all the
>> >>> semantics of `volatile', and more.
>> >>>
>> >>> `volatile` is not strong enough to build thread-safe immutable
>> >>> objects, `final` is.
>> >>>
>> >>> On Wed, Oct 3, 2012 at 8:24 AM, Andy Nuss <andrew_nuss at yahoo.com>
>> >>> wrote:
>> >>> > Hi,
>> >>> >
>> >>> > I have a class with a single member, a reference to a new
>> >>> > MessageDigest
>> >>> > obtained in the constructor based on the algorithm name passed to
>> >>> > the
>> >>> > constructor.  The constructor also has a Reader argument and reads
>> >>> > all
>> >>> > the
>> >>> > data from the Reader thru an OutputStreamWriter("UTF-8) and passes
>> >>> > thru
>> >>> > to
>> >>> > the digest with my own OutputStream filter.  The call to the
>> >>> > constructor
>> >>> > then accesses the MessageDigest member and calls digest() to get the
>> >>> > resulting byte[].  My code by all appearances is single threaded,
>> >>> > but I
>> >>> > am
>> >>> > having strange bugs that on one particular machine running vmware,
>> >>> > the
>> >>> > digest result I am getting (for password hashing) appears not to be
>> >>> > repeatable.
>> >>> >
>> >>> > Basically, I am wondering if another thread can execute the body of
>> >>> > the
>> >>> > constructor (or in the construction and use of the
>> >>> > OutputStreamWriter,
>> >>> > within my constructor) that could be causing a bug where memory
>> >>> > written
>> >>> > by
>> >>> > the MessageDigest.update() function (triggered within the
>> >>> > constructor
>> >>> > by
>> >>> > writing thru OutputStreamWriter) is not seen in the call to digest()
>> >>> > on
>> >>> > the
>> >>> > newly created MessageDigest member after the constructor returns.
>> >>> >
>> >>> > Andy
>> >>> >
>> >>> > _______________________________________________
>> >>> > 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