While reading Java docs on Memory Consistency errors. I find points related to two actions that creates happen - before relationship:
When a statement invokes Thread.start()
, every statement that has a
happens-before relationship with that statement also has a
happens-before relationship with every statement executed by the new
thread. The effects of the code that led up to the creation of the
new thread are visible to the new thread.
When a thread terminates and causes a Thread.join()
in another thread
to return, then all the statements executed by the terminated
thread have a happens-before relationship with all the statements
following the successful join. The effects of the code in the thread
are now visible to the thread that performed the join.
I am not able to understand their meaning. It would be great if someone explain it with a simple example.
Modern CPUs don't always write data to memory in the order it was updated, for example if you run the pseudo code (assuming variables are always stored to memory here for simplicity);
a = 1
b = a + 1
...the CPU may very well write b
to memory before it writes a
to memory. This isn't really a problem as long as you run things in a single thread, since the thread running the code above will never see the old value of either variable once the assignments have been made.
Multi threading is another matter, you'd think the following code would let another thread pick up the value of your heavy computation;
a = heavy_computation()
b = DONE
...the other thread doing...
repeat while b != DONE
nothing
result = a
The problem though is that the done flag may be set in memory before the result is stored to memory, so the other thread may pick up the value of memory address a before the computation result is written to memory.
The same problem would - if Thread.start
and Thread.join
didn't have a "happens before" guarantee - give you problems with code like;
a = 1
Thread.start newthread
...
newthread:
do_computation(a)
...since a
may not have a value stored to memory when the thread starts.
Since you almost always want the new thread to be able to use data you initialized before starting it, Thread.start
has a "happens before" guarantee, that is, data that has been updated before calling Thread.start
is guaranteed to be available to the new thread. The same thing goes for Thread.join
where data written by the new thread is guaranteed to be visible to the thread that joins it after termination.
It just makes threading much easier.