This example is really nasty (and slightly wrong misses a third option which I suspect is more likely than 0) and I've seen it happen in the real world , first the code can go into an infinite loop and second produce either value (PS to make the example even worse make that int a long for some real (theoretical) fun) ...
Formally the write can never be determined to have "happened before" any subsequent read by the other thread and therefore can disappear in a puff of JVM / OS / CPU logic :-) . This isn't a bug by the way its kind of a performance feature ;-) . So write true or write 42 maybe invisible to the second thread forever or not ;-)
Java memory model
http://jcp.org/en/jsr/detail?id=133
Really we should just stop the conversation here as the why doesn't matter an any particular examples are dangerous in that if you defeat one of my arguments you may think your ok when something else can get you but what the hey ...
There are actually a couple of reasons why this can fail and they are dependent on what you actually run your java on ;-) ...
Here are SOME gross simplifications of stuff that can happen (these are just examples probably bad ones :-) ) ...
i) Lack of memory barrier /
fence thread A writes true to its cache but never commits that cache to memory, thread B runs on a different CPU with a different cache it reads but does so from its cache and never has to read the real bool (or int) value. OS / CPU calls exist to cause both read and write caches to drop but you never asked Java\OS\thread lib\CPU to do that ;-) [assumes no cache snooping etc blah , blah ;-) ]
What is a memory barrier ...
http://en.wikipedia.org/wiki/Memory_barrier
Java 7 memory fence API ...
http://cs.oswego.edu/pipermail/concurrency-interest/2009-January/005743.html
ii) Compiler optimisation ...
Turns out because you said you didn't care about the flag (i.e. not volatile etc) being read between threads its legal for Java (for speed) to do this ...
while (flag)
{
// do something that doesn't modify flag
}
can turn into this .....
if (flag)
while (true)
{
// do something that doesn't modify flag
}
so by the time you set true , Java ain't listening any more ;-) its
testing true which is always true
Blog on compiler optimisations ...
http://www.novell.com/communities/node/12062/friends-optimizing-compilers-who-needs-enemies-volatile-variables-loop-invariants-and-thr