Technically speaking, all you need to work with class members shared by two or more thread is
lock. Please see:
http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html[
^].
This task is interesting by the reason not directly related to the techniques of thread synchronization, but due to its effect on semantic. This is classical example of
race condition
, see
http://en.wikipedia.org/wiki/Race_condition[
^]. This is just a technical term. I used to lean about this phenomenal with the use of different, more definitive term "
incorrect dependency of the order of execution". This is exactly what it is.
In this example, the output of the code in unpredictable, despite of correct thread synchronization: sometimes main thread may print incremented, sometimes non-incremented values, because nothing guarantees any certain order of the operation on the shared memory: sometimes can print and later increment, sometime it can increment and then print. (However, these variants could come with very different probabilities; this is a danger of race conditions: a program may work millions of time in expected order but eventually change the order the way it defeats its purpose.)
I hope the sole purpose of this code would be exactly this: to demonstrate race condition. This is no any practical sense in using threads for such tasks.
—SA