[concurrency-interest] final field/constructor visibility (cf. CyclicBarrier)

Vitaly Davidovich vitalyd at gmail.com
Sat Sep 27 15:04:26 EDT 2014


I think you're right from JMM standpoint, but in practice Hotspot doesn't
track final fields individually.  It records whether any final field is
written in a ctor, and if so, emits barriers.  So in reality, at least on
today's hotspot version, it will work as if both were final.

Sent from my phone
On Sep 27, 2014 8:19 AM, "thurstonn" <thurston at nomagicsoftware.com> wrote:

> I have a question regarding the memory semantics of a constructor that sets
> both a final and non-final field.
>
> It was triggered by looking at j.u.c.CyclicBarrier which is defined:
>
> <code>
> final int parties
> int count
>
> CyclicBarrier(int parties)
>    this.parties = parties;
>    this.count = parties;
> </code>
>
> Now my understanding of the JMM is that any thread referencing the CB is
> guaranteed to see  CB#parties as expected, but there is no guarantee that a
> thread can't see CB#count = 0 //initialized state, i.e. the fact that the
> constructor sets a final variable (#parties) has no bearing at all on any
> guarantees of the visibility of #count (and as a side note, the code order
> of the writes has no bearing at all either, i.e.
>
> <code>
> final int parties
> int count
>
> CyclicBarrier(int parties)
>     this.count = parties;
>     this.parties = parties;
>
> </code>
>
> has the same issue.
>
> So the following is theoretically possible
> T1                            T2
> x = new CB(5)             assert x.getCount() == 5  //may fail
>
> Now CB takes great care that all access of #count is under protection of a
> lock (both reads and writes), but there is no happens-before edge between
> the constructor writing to non-final #count and T2 (or T3, T4) acquiring
> the
> lock and then reading #count.
> In short (although there is a high presumption that the JDK is correct), CB
> does not look multi thread-safe (to me).
>
> I was expecting to see:
>
> <code>
> CyclicBarrier(int parties)
>     this.lock.lock();
>     this.count = parties;
>     this.lock.unlock();
>     this.parties = parties;
>
> </code>
> or something similar (of course the lock#lock() would be uncontended and so
> shouldn't present any substantial performance cost); this would provide the
> necessary happens-before edge (release of lock happens-before any
> subsequent
> acquisition of said lock).
>
>
> As a side note, this is not the situation that generally causes confusion
> with respect to final field visibility guarantees, e.g. where a constructor
> writes a final Map field and then populates the Map (I think that's been
> settled?)
>
> Someone want to set me straight?
>
>
>
>
>
>
> --
> View this message in context:
> http://jsr166-concurrency.10961.n7.nabble.com/final-field-constructor-visibility-cf-CyclicBarrier-tp11306.html
> Sent from the JSR166 Concurrency mailing list archive at Nabble.com.
> _______________________________________________
> 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/20140927/ad857059/attachment.html>


More information about the Concurrency-interest mailing list