From: Andreas Leitgeb on
Jim Janney <jjanney(a)shell.xmission.com> wrote:
> Andreas Leitgeb <avl(a)gamma.logic.tuwien.ac.at> writes:
>> Has anyone found e.g. an english 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?
> All strings of the form "\0", "\0\0", "\0\0\0", etc.
Well, they're *almost* trivial ;-)

> For ordinary words, I ran the following against the
> dictionary file on a Linux system and got no hits.
Thanks for the code (I guess I'd have been too lazy, myself ;)

I ran it against all the pure class-names (like "java.lang.String",
and "java/lang/String") from $JAVA_HOME/lib/rt.jar and found no
match, either. Not even for each "Lpath/to/ClassName;".

From: Andreas Leitgeb on
markspace <nospam(a)nowhere.com> wrote:
>> As stooges is private and has not even got a getter, your class would
>> still be immutable even without the "final" keyword.
>
> This bit I don't think is true. I'm pretty sure the JLS only guarantees
> visibility of these fields due to the presences of the final keyword.
> See the Final Fields section of the JLS, section 17.5 iirc.

SomeClass: has a plain int-field initialized from its C'tors param.

some_shared_field: e.g. a non-final static field of a class known
to both threads.

Thread A doing:
some_shared_field = new SomeClass(42);

Thread B doing:
SomeClass sc=some_shared_field;
if (sc != null) { do_something_with(sc); }

Assuming that Thread B ever sees a non-null value in sc, I'd be very
surprised, if it then might ever see a *non-fully-initialized* instance,
even if SomeClass *doesn't* have final fields.

Not noticing changes in a plain field is one thing, but reading an old
value of something that wasn't so far seen by that thread... well,
that's beyond me. And, that adding a (dummy) final field to SomeClass
(e.g. one that's just "initialized to 0 in the c'tor) might solve that
problem is even further beyond me.

From: Daniel Pitts on
On 7/27/2010 1:45 PM, Andreas Leitgeb wrote:
> markspace<nospam(a)nowhere.com> wrote:
>>> As stooges is private and has not even got a getter, your class would
>>> still be immutable even without the "final" keyword.
>>
>> This bit I don't think is true. I'm pretty sure the JLS only guarantees
>> visibility of these fields due to the presences of the final keyword.
>> See the Final Fields section of the JLS, section 17.5 iirc.
>
> SomeClass: has a plain int-field initialized from its C'tors param.
>
> some_shared_field: e.g. a non-final static field of a class known
> to both threads.
>
> Thread A doing:
> some_shared_field = new SomeClass(42);
>
> Thread B doing:
> SomeClass sc=some_shared_field;
> if (sc != null) { do_something_with(sc); }
>
> Assuming that Thread B ever sees a non-null value in sc, I'd be very
> surprised, if it then might ever see a *non-fully-initialized* instance,
> even if SomeClass *doesn't* have final fields.
>
> Not noticing changes in a plain field is one thing, but reading an old
> value of something that wasn't so far seen by that thread... well,
> that's beyond me. And, that adding a (dummy) final field to SomeClass
> (e.g. one that's just "initialized to 0 in the c'tor) might solve that
> problem is even further beyond me.

My understanding is that its related to memory barriers, and CPU L1, L2
caches. The problem is even more confounding in that you might read an
object state on Thread B that was *never* a valid state.

I'm not sure that a dummy final field would actually prevent the
problem, I think that the guarantee is only on the fields which are
final (I could be wrong about that though).


--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
From: Patricia Shanahan on
Andreas Leitgeb wrote:
> markspace <nospam(a)nowhere.com> wrote:
>>> As stooges is private and has not even got a getter, your class would
>>> still be immutable even without the "final" keyword.
>> This bit I don't think is true. I'm pretty sure the JLS only guarantees
>> visibility of these fields due to the presences of the final keyword.
>> See the Final Fields section of the JLS, section 17.5 iirc.
>
> SomeClass: has a plain int-field initialized from its C'tors param.
>
> some_shared_field: e.g. a non-final static field of a class known
> to both threads.
>
> Thread A doing:
> some_shared_field = new SomeClass(42);
>
> Thread B doing:
> SomeClass sc=some_shared_field;
> if (sc != null) { do_something_with(sc); }
>
> Assuming that Thread B ever sees a non-null value in sc, I'd be very
> surprised, if it then might ever see a *non-fully-initialized* instance,
> even if SomeClass *doesn't* have final fields.
>
> Not noticing changes in a plain field is one thing, but reading an old
> value of something that wasn't so far seen by that thread... well,
> that's beyond me. And, that adding a (dummy) final field to SomeClass
> (e.g. one that's just "initialized to 0 in the c'tor) might solve that
> problem is even further beyond me.
>

Remember that many systems allow threads to move from processor to
processor. Thread B, running on Processor 42, may see an old value of a
cache line it has never referenced because Thread A recently used a time
slice on Processor 42, and nothing has since happened to remove the line
from the Processor 42 cache. Thread A has since executed a store into
that cache line on Processor 5, but Processor 42 has not heard about
that yet.

It is up to the Java implementation to do whatever is needed, including
inserting memory barrier commands, to ensure that behavior conforms to
what the JLS says.

Patricia
From: markspace on
Andreas Leitgeb wrote:

> Assuming that Thread B ever sees a non-null value in sc, I'd be very
> surprised, if it then might ever see a *non-fully-initialized* instance,
> even if SomeClass *doesn't* have final fields.
>
> Not noticing changes in a plain field is one thing, but reading an old
> value of something that wasn't so far seen by that thread... well,
> that's beyond me. And, that adding a (dummy) final field to SomeClass
> (e.g. one that's just "initialized to 0 in the c'tor) might solve that
> problem is even further beyond me.


As other's have pointed out, yes that's exactly what can happen. Given
enough executions, it will.

Besides the whole L1, L2 cache thing there's a memory controller that
sits on top of the cache that can return previous values written by any
CPU in any order, even if they haven't hit the cache yet. It's the
possibility out pulling out some values from another CPUs write stream,
without checking for other writes, that makes this all so unpredictable.

And writes are discreet things to the cache controller, it doesn't know
that write1 matters and has to come before write2. If you ask for
write2 and don't synchronize with write1, then you'll only get write2,
just what you asked for.

To summarize:

class SomeClass {
int value;
public SomeClass( int i ) { value = i; }
}

class Shared {
public SomeClass shared;

public void set() { shared = new SomeClass(42); }
}

is straight out of Java Concurrency in Practice and is definitely not
thread safe. See page 50, the "holder" example. Adding a check for
"shared" equal to null first won't help. You will eventually get a
garbage read.