From: Lew on
Lew wrote:
>> Yes. Don't omit what tom said about /happens-before/:
>>> In fact, it's worse than that. Thread A could finish the method and update
>>> both calculated and code, but because there is no happens-before relationship
>>> between thread A and thread B, it's possible that B could come along later,
>>> and see the updated calculated but *not* the updated code. So even without
>>> an unlucky timeslice end, there is no guarantee of safety here.

Andreas Leitgeb wrote:
> There is still a misunderstanding - I'm just not sure if it's on my or your
> side.
> Thread 1 assigns two plain word-sized fields: a and then b.
> can Thread 2 happen to see b's new value, and (after that) a's old value?

Yes.

> Tom's explanation was (as far as I understood it) based on the code-sample
> where the flag was set before the code, and he rightly pointed out that this
> gap may be even much longer than expected. Can it reverse, as well?

Yes.

When thread A changes values for shared data 'a' and 'b' without establishment
of /happens-before/, at some later time (even chronologically after both
values were changed), a different thread B can examine those data and find any
of four states: the old value for both 'a' and 'b', the old value for 'a' and
new for 'b', the new value for 'a' and old for 'b', or the new value for both.

You'll need multiple cores to encounter these scenarios, most likely, and it
will depend on whether they use a NUMA, various caching strategies, how far
apart in the memory architecture the cores are, the load at the time, ...

Andreas Leitgeb wrote:
>>> Has anyone found e.g. an english [sic] dictionary-word with hashCode 0, yet?
>>> Or perhaps the name of some commonly used class in Java standard library
>>> or some other String likely occurring in innocent code?

Lew wrote:
>> ""

Andreas Leitgeb wrote:
> Damn, I shouldn't have trimmed the "non-trivial" that I had already written.
> At least, the hashCode for "" is quite efficiently obtained.

It's not really trivial. "" is an extremely common 'String' value and
frequently can be the key to a hashed structure, so its hash value is relevant.

--
Lew
From: Patricia Shanahan on
Andreas Leitgeb wrote:
> Lew <noone(a)lewscanon.com> wrote:
>> Tom Anderson wrote:
>>>> To make this method safe, you either have to synchronize the whole thing,
>>>> or do the update of calculated and code atomically at the end.
>> Andreas Leitgeb wrote:
>>> I'd have expected that if "calculated" was assigned *after* "code", that
>>> would suffice without further synchronisation or volatile-ity of the fields.
>>> Am I still too naive?
>> Yes. Don't omit what tom said about /happens-before/:
>>> In fact, it's worse than that. Thread A could finish the method and update
>>> both calculated and code, but because there is no happens-before relationship
>>> between thread A and thread B, it's possible that B could come along later,
>>> and see the updated calculated but *not* the updated code. So even without
>>> an unlucky timeslice end, there is no guarantee of safety here.
>
> There is still a misunderstanding - I'm just not sure if it's on my or your
> side.
> Thread 1 assigns two plain word-sized fields: a and then b.
> can Thread 2 happen to see b's new value, and (after that) a's old value?
>
> Tom's explanation was (as far as I understood it) based on the code-sample
> where the flag was set before the code, and he rightly pointed out that this
> gap may be even much longer than expected. Can it reverse, as well?

Depends on the memory order rules in the hardware. I'm most familiar
with the rules for SPARC v9, but other processors have their own rules.
In Total Store Order they cannot reverse. In Relaxed Memory Order and
Partial Store Order, they can reverse, from the point of view of other
processors, unless some action such as a membar #StoreStore forces ordering.

See
http://en.wikipedia.org/wiki/Memory_ordering#In_SMP_microprocessor_systems

Patricia
From: Andreas Leitgeb on
Lew <noone(a)lewscanon.com> wrote:
> Andreas Leitgeb wrote:
>> Thread 1 assigns two plain word-sized fields: a and then b.
>> can Thread 2 happen to see b's new value, and (after that) a's old value?
> Yes.

>> Tom's explanation was (as far as I understood it) based on the code-sample
>> where the flag was set before the code, and he rightly pointed out that this
>> gap may be even much longer than expected. Can it reverse, as well?
> Yes.

> When thread A changes values for shared data 'a' and 'b' without establishment
> of /happens-before/, at some later time (even chronologically after both
> values were changed), a different thread B can examine those data and find any
> of four states: the old value for both 'a' and 'b', the old value for 'a' and
> new for 'b', the new value for 'a' and old for 'b', or the new value for both.

Thanks for ultimate clarification!

> Andreas Leitgeb wrote:
>>>> Has anyone found e.g. an english [sic] dictionary-word with hashCode 0, yet?
>>>> Or perhaps the name of some commonly used class in Java standard library
>>>> or some other String likely occurring in innocent code?
> Lew wrote:
>>> ""
> Andreas Leitgeb wrote:
>> Damn, I shouldn't have trimmed the "non-trivial" that I had already written.
>> At least, the hashCode for "" is quite efficiently obtained.
> It's not really trivial. "" is an extremely common 'String' value and
> frequently can be the key to a hashed structure, so its hash value is relevant.

The empty String *is* trivial, and triviality doesn't imply uncommonness or
irrelevance. The hashcode of "" doesn't take long to compute, but if e.g. a
String like "java.lang.String" had an hashCode of 0, then the necessity to
recalc it each time might be more noticeable/relevant than for "".

From: Andreas Leitgeb on
Patricia Shanahan <pats(a)acm.org> wrote:
> Andreas Leitgeb wrote:
>> Thread 1 assigns two plain word-sized fields: a and then b.
>> can Thread 2 happen to see b's new value, and (after that) a's old value?
> Depends on the memory order rules in the hardware. I'm most familiar
> with the rules for SPARC v9, but other processors have their own rules.
> In Total Store Order they cannot reverse. In Relaxed Memory Order and
> Partial Store Order, they can reverse, from the point of view of other
> processors, unless some action such as a membar #StoreStore forces ordering.
> See
> http://en.wikipedia.org/wiki/Memory_ordering#In_SMP_microprocessor_systems

Thanks for the processor-specific infos.
It means, that an attempt to "produce" such a reversion (in the sense as
one can "produce" a deadlock) may be doomed if on the "wrong" platform.

From: Peter Duniho on
Andreas Leitgeb wrote:
> Patricia Shanahan <pats(a)acm.org> wrote:
>> Andreas Leitgeb wrote:
>>> Thread 1 assigns two plain word-sized fields: a and then b.
>>> can Thread 2 happen to see b's new value, and (after that) a's old value?
>> Depends on the memory order rules in the hardware. I'm most familiar
>> with the rules for SPARC v9, but other processors have their own rules.
>> In Total Store Order they cannot reverse. In Relaxed Memory Order and
>> Partial Store Order, they can reverse, from the point of view of other
>> processors, unless some action such as a membar #StoreStore forces ordering.
>> See
>> http://en.wikipedia.org/wiki/Memory_ordering#In_SMP_microprocessor_systems
>
> Thanks for the processor-specific infos.
> It means, that an attempt to "produce" such a reversion (in the sense as
> one can "produce" a deadlock) may be doomed if on the "wrong" platform.

Keep in mind that it's not just hardware implementation that affects
this. Compiler optimizations can change the order of reads and writes
as well.

The bottom line is that if the order of reads and writes is important,
there needs to be some kind of synchronization in the code to accomplish
that. It may be sufficient to specify "volatile", or a more costly
synchronization technique may be needed (such as acquiring the monitor
for an object).

This is true even if running the code on a single-core CPU.

Presumably, the choice of the existing hashCode() implementation for
String was made based on the assumption that the overhead of even
"volatile" was more important to avoid than the remote possibility that
multiple threads may wind up calculating the hash code for the same
string instance.

And, also presumably, this is the same thinking that led to the code in
which those unfortunate strings with a hash code of 0 always wind up
getting recalculated no matter what (because otherwise, one would need a
flag, separate from the hash code field, which could wind up out-of-sync
with the hash code field absent synchronization, such as "volatile"�as
discussed previously in this thread).

Pete