I am new to threads, and I must say I have never spent more time understanding any other topic for the SCJP than this. Anyway, I wrote this simple threads program and I can't understand how the result was arrived at. Program and result are shown below.
My question is regarding lines 7 and 9.There seems to be a jump in the value of "i" from 3 to 5, without first going thru 4, which shows up later. How can this be possible?
+ T0 and T1 both enter the for loop and execute #8.
+ T0 executes the (++i) in #9 and increments the shared variable.
+ T1 executes the (++i) in #9 as well as the println(...)
+ T0 executes the println(...) in #9.
All you have to keep in mind here is that expressions are evaluated from inside to outside. println(++i) is executed as 1. (++i); 2. println(...);
It is very important to know what operations are executed atomically (as in: This statement executes fully or it doesn't, but there are no intermediate states). By that definition, and this is a common pitfall for people new to threading, (i++) is not atomic either, as it is a shorthand for 1. get i, 2. increment what you got, 3. write the result to i.
To add to that, one of the reasons that this printout is somewhat (relatively) stable, is because the program is doing I/O. The I/O is causing the threads to flush it registers (along with adding time between the portions of code which access the unsafe variable).
If I/O was not done, meaning the loops were doing lots of iterations, there will not only be more "skips" (or "jumps"), but there will also be cases where the value seems to go "backwards". Of course, you won't be able to see it without the I/O printouts -- sort of a case of Schrodinger's Cat ...
Nikhil Pujari wrote:The thought that println may not be an atomic operation did cross my mind, but I wasn't sure. Thanks again.
No method call is ever atomic. About the only things that are atomic are reading from and writing to variables, except that reading/writing longs and doubles is not atomic if the variables in question are not declared volatile. Of course, we can make any chunk of code behave as if it were atomic with the proper use of synchronization or the higher level constructs in java.util.concurrent.