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 [email protected].
For more options, visit https://groups.google.com/d/optout.