"It will also see versions of any object or array referenced by those
final fields that are **at least as up-to-date as the final fields**
are."

To me this means that the value of the final field will be correctly
published **as of the time it was assigned**. So in your example,
there are two problems, I think:

* The modification that is done at the second line of the constructor
of Foo is **not**, in my understanding, safely published, since it is
"more recent" than the final field's assignment (reversing the two
lines *would*, in my understanding, safely publish the array, though
it would still not guarantee an ordering between the fill(1) and
fill(2) operations in this case);
* The value of the bytes array, when the second thread gets hold of
it, is not specified: the bytes variable itself is volatile, but not
its content, so the assignment to bytes must have occurred, but not
the filling with ones.

So, since the previous value of (the contents of) bytes is not
specified, and the next value of bytes is not safely published, in my
view, for this code, all bets are off as to the value seen by the
first thread on the "match" line. No combination of ones and twos
would surprise me (and I'm not even so sure about zeroes).

On 9 May 2014 17:41, Mike Fikes <mikefi...@me.com> wrote:
> Thanks Alexandru! That was insightful. :)
>
> Even the JLS's (non-normative?) text is confusing IMHO. Section 17.5 ends
> with this paragraph:
>
> The usage model for final fields is a simple one. Set the final fields for
> an object in that object's constructor. Do not write a reference to the
> object being constructed in a place where another thread can see it before
> the object's constructor is finished. If this is followed, then when the
> object is seen by another thread, that thread will always see the correctly
> constructed version of that object's final fields. It will also see versions
> of any object or array referenced by those final fields that are at least as
> up-to-date as the final fields are.
>
> If you read that paragraph, it would lead you to believe the bit in bold
> would be applicable to the program below. It seems that the key is, as you
> pointed out, simply extending the concept of "this escaping" to cover
> mutable references stored during construction.
>
> import java.util.Arrays;
>
> public class Main {
>
>     static class Foo {
>         final byte[] bytes;
>         Foo(byte[] bytes) {
>             this.bytes = bytes;
>             Arrays.fill(this.bytes, (byte) 2);
>         }
>     }
>
>     static volatile byte[] bytes;
>     static volatile Foo foo;
>
>     public static void main(String[] args) {
>
>         new Thread(new Runnable() {
>             public void run() {
>                 // Create an array filled with 1s and spin for other thread
>                 bytes = new byte[1024*1024];
>                 Arrays.fill(bytes, (byte) 1);
>                 while (foo == null) {}
>
>                 // Check to see if we get the array contents set by other
> thread
>                 byte[] expected = new byte[1024*1024];
>                 Arrays.fill(expected, (byte) 2);
>                 boolean match = Arrays.equals(expected, foo.bytes);
>                 System.out.println(match); // Will print false at times
>             }
>         }).start();
>
>         new Thread(new Runnable() {
>             public void run() {
>                 // Spin for first thread
>                 while (bytes == null) {}
>
>                 // Create an "immutable" object using bytes, while mutating
> bytes prior to construction completion and publication
>                 foo = new Foo(bytes);
>             }
>         }).start();
>     }
> }
>
>
> On Thursday, May 8, 2014 4:43:10 PM UTC-4, Alexandru Nedelcu wrote:
>>
>> On Wed, May 7, 2014 at 6:31 AM, Alex Miller <al...@puredanger.com> wrote:
>>>
>>> It does matter with regard to visibility across threads - your example
>>> does not use a synchronization mechanism and there is no guarantee that
>>> other threads will ever see those changes (so don't ever ever do that :).
>>> But if you stick to the normal Clojure apis, all is good. I'd highly
>>> recommend reading JCIP to dive into the details.
>>>
>>> Final field freeze is particularly weird and it baked my noodle when I
>>> first encountered it - here's a blog I wrote about it approx 697 years ago
>>> in internet time (and Brian Goetz backs me up in the comments :)
>>> http://tech.puredanger.com/2008/11/26/jmm-and-final-field-freeze/
>>
>> I believe that while JCIP is useful, it is also confusing, because it is
>> trying to explain Java’s memory model in layman’s terms. I recently
>> experienced “enlightenment”, by making an effort to understand how things
>> work at a lower level.
>>
>> Happens-before relationships / ordering guarantees are given by the
>> compiler, in combination with the CPU, with the rules being implied by usage
>> of memory fences (barriers). Without ordering guarantees, several things can
>> happen - the compiler could optimize the code by reordering or eliminating
>> instructions, the CPU might optimize the code by reordering or eliminating
>> instructions and - what bits beginners the most - today’s multi-core CPUs
>> are tricky, as each CPU has a store buffer that’s local to each core (i.e.
>> other cores cannot see it) and published values only become visible to other
>> cores when the store buffer gets flushed to the L1 cache. And you have no
>> guarantee that this flush will ever happen, or even after it happens, you
>> have no guarantee that other processors that already have a cached value
>> will make an effort to read the more up-to-date value … unless ordering
>> semantics are enforced. And actually thinking in terms of flushes to memory
>> is dangerous, as nothing you do guarantees a flush - everything being
>> relative, specified in terms of happens-before relationships, implied by
>> memory barriers.
>>
>> And memory barriers are tricky beasts, as they come in multiple shapes and
>> sizes. The JSR 133 Cookbook is a useful document for shedding some light on
>> how they work. In particular, for final fields, you get a guarantee for a
>> StoreStore memory barrier, like so:
>>
>> x.finalField = v; *StoreStore*; sharedRef = x;
>>
>> This guarantee basically says that the finalFields’ value will always be
>> stored before the write sharedRef = x happens. Or in other words, once the
>> constructor of x is finished and the value stored inside a sharedRef, the
>> finals are already fully initialized. And this extends to whatever writes
>> that happened in the object stored in that final field too. This assumes
>> that this didn’t escape during construction - in which case the above
>> guarantee becomes meaningless for threads that already saw object x. As an
>> aside, a StoreStore fence on X86 is a no-op, as stores on X86 are ordered,
>> but for other processors this is not true and the compiler can and does
>> reorder instructions by itself.
>>
>> Also consider doing something like:
>>
>>  final int[] field = new int[] {1,2,3,4}
>>
>> Even though that array is not immutable, the array and the values in it
>> will be visible once the final field itself becomes visible, again because
>> of the store ordering guarantee. But this doesn’t hold if that array
>> reference has been seen before, so this doesn’t work as people might think:
>>
>> final int[] field;
>> public Constructor(int[] arr) { field = arr }
>>
>> My initial impression was that a final field store behaves like a volatile
>> write. That’s not true. A volatile write is preceded by a StoreStore, while
>> a final write is succeeded by one. Also, a volatile write followed by a
>> volatile read guarantees a Store/Load memory barrier between the two actions
>> for ordering previous stores with subsequent loads - this is the rule that
>> says that once a volatile is stored, then subsequent reads are ordered after
>> that store (so the volatile read is basically monitor enter and the volatile
>> write is basically monitor exit … the similarity with acquiring locks is not
>> accidental at all) and so threads don’t get stale data. Finals don’t get the
>> same treatment, even though there are similarities between the two … this is
>> also why it is important for this to not escape during construction or for
>> why the array reference received from the outside in the above won’t
>> necessarily be up-to-date when the final will be observed by other threads -
>> again, ordering guarantees are relative.
>>
>> In other words, for finals to work properly, this mustn’t escape during
>> construction and care must be taken when storing references to mutable
>> things received from the outside.
>>
>> --
>> Alexandru Nedelcu
>> www.bionicspirit.com
>>
>> PGP Public Key:
>> https://bionicspirit.com/key.aexpk
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to