Well, I was wrong on the internet. (Again).

Vladimir is right, the happens-before is transitive. Regardless of the 
order of execution on either side, every field initialization (final or 
otherwise) happens-before the put(), and therefor happens-before any 
subsequent get() on any thread, such that the get()'ing thread cannot 
observe pre-initialization values in the value being put() in the CHM.

For others that might follow the confusing weekend logic that led me to the 
mistake: I need to remind myself that it is complicated (and error-prone) 
to deduce negatives from positive observations. E.g. "happened before" just 
means "there is no happens-before that prohibited it from being observed 
this way" (from JLS 1.4.5: "...Informally, a read r is allowed to see the 
result of a write w if there is no happens-before ordering to prevent that 
read.").

The process of making this mistake (for me) comes it comes from figuring 
out too many negatives in a row, as in when trying to fully figure out the 
meaning of "anti-anti-anti-missile-missile" in your head, without unfolding 
it on paper. It can lead to falsely jumping from "I have an example where I 
definitely saw A happen before B happened" to hb(A, B) instead of just the 
!hb(B, A) it actually means. And/or something like that backward.

For me, these multi-deep-negatives thinking sequence often start with 
something informal like "so we know that another thread *can* see 
pre-initialized values of non-final fields if the reference to the object 
was published without an ordering operation of some sort" followed by "so 
since I know that is allowed, what is it in this stuff [like the CHM 
put()/get() example above] that actually prevents it from happening in this 
case?", then, after finding the concrete ordering operation [the volatile 
write and read] in the implementation but not stated *directly* in the 
contract (now we are in a two-deep negative assessment), taking the path of 
"I can construct a sequence where I *know* that an initialization of a 
field in an object happened before a publication of the object, and where 
without this ordering operation another thread could still see a value that 
predates that initialization, so if I remove this implementation-specific 
ordering operation this can still happen under this contract" takes me into 
a triple negative territory.

The best thing to do is to erase the board and start from the other end...

The contract's happens-before statement between the put() and subsequent 
non-null get()s, even while not directly saying anything about the 
relationships with program operations prior to the put(), does carry a 
transitive property that covers them. So the contract would require all 
future implementations to apply some ordering operation(s) that would still 
enforce the happens-before, including its transitive properties.  What that 
operation would be doesn't matter, it is the implementor's responsibility 
to make sure it is there.

On Sunday, November 18, 2018 at 2:37:27 AM UTC-8, Vladimir Sitnikov wrote:
>
> Gil>I'd be happy
>
> I wish you all the best. I truly adore the way you explain things.
>
> Gil>There is no contract I've found that establishes a 
> happens-before relationship between the initialization of non-final fields 
> in some object construction and the put of that object (or of some object 
> that refers to it) as a value into the CHM.
>
> In this case that contract is provided by JLS "17.4.3. Programs and 
> Program Order" and "17.4.5. Happens-before Order" .
> TL;DR: "If x and y are actions of the same thread and x comes before y in 
> program order, then hb(x, y)."
>
> Let me take an example:
>
> class Wrapper {
>   int value;
> }
> static CHM map;
>
> Thread1:
> val w = new Wrapper();
> w.value=42;
> map.put("wrap", w);
>
> Thread2:
> val u = map.get("wrap");
> if (u != null) { println(u.value); }
>
> 1) In thread 1 there's happens-before between write "value=42", and write 
> of "w" into the map since "program order implies happens-before"
> 2) CHM provides happends-before for non-null retrieval of the value
> 3) "retrieval of the value u" happens-before "read of u.value" since 
> "program order implies happens-before"
>
> The happens-before order is a partial order, so it is transitive, so 1+2+3 
> gives "write of value=42 happens-before read of u.value".
> The key point of having a CHM is to have 2 (happens-before across threads) 
> which is not provided automatically if simple HashMap is used.
>
> What do you think?
>
> Gil>It is true that* in current implementation* a put() involves a 
> volatile store
>
> JavaDoc contract is there, so CHM would provide "happens-before relation 
> between update and non-null retrieval" in future one way or another.
>
> Vladimir
>

-- 
You received this message because you are subscribed to the Google Groups 
"mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to mechanical-sympathy+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to