This example is similar to that in the preceding section, except that one method
assigns to both variables and the other method reads both variables. Consider a
class that has class variables a
and b
and methods to
and fro
:
class Simple { int a = 1, b = 2; void to() { a = 3; b = 4; } void fro() { System.out.println("a= " + a + ", b=" + b); } }
Now suppose that two threads are created, and that one thread calls to
while the
other thread calls fro
. What is the required set of actions and what are the ordering constraints?
Let us consider the thread that calls to
. According to the rules, this thread must perform an assign of a
followed by an assign of b
. That is the bare minimum required to execute a call to the method to
. Because there is no synchronization, it is at the option of the implementation whether or not to store the assigned values back to main memory! Therefore the thread that calls fro
may obtain either 1
or 3
for the value of a
, and independently may obtain either 2
or 4
for the value of b
.
Now suppose that to
is synchronized
but fro
is not:
class SynchSimple { int a = 1, b = 2; synchronized void to() { a = 3; b = 4; } void fro() { System.out.println("a= " + a + ", b=" + b); } }
In this case the method to
will be forced to store the assigned values back to main
memory before the unlock action at the end of the method. The method fro
must,
of course, use a
and b
(in that order) and so must load values for a
and b
from
main memory.
The total set of actions may be pictured as follows:
Here an arrow from action A to action B indicates that A must precede B.
In what order may the actions by the main memory occur? Note that the rules do not require that write a
occur before write b
; neither do they require that read a
occur before read b
. Also, even though method to
is synchronized
, method fro
is not synchronized
, so there is nothing to prevent the read actions from occurring between the lock and unlock actions. (The point is that declaring one method synchronized
does not of itself make that method behave as if it were atomic.)
As a result, the method fro
could still obtain either 1
or 3
for the value of a
, and independently could obtain either 2
or 4
for the value of b
. In particular, fro
might observe the value 1
for a
and 4
for b
. Thus, even though to
does an assign to a
and then an assign to b
, the write actions to main memory may be observed by another thread to occur as if in the opposite order.
Finally, suppose that to
and fro
are both synchronized
:
class SynchSynchSimple { int a = 1, b = 2; synchronized void to() { a = 3; b = 4; } synchronized void fro() { System.out.println("a= " + a + ", b=" + b); } }
In this case, the actions of method fro
cannot be interleaved with the actions of method to
, and so fro
will print either "a=1, b=2
" or "a=3, b=4
".