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.