Consider the following program from the JLS section on volatile fields
class Test {
static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
Consider two thread are concurrently executing method one()
and two()
.
JLS states the following:
This allows method one and method two to be executed concurrently, but guarantees that accesses to the shared values for i and j occur exactly as many times, and in exactly the same order, as they appear to occur during execution of the program text by each thread. Therefore, the shared value for j is never greater than that for i, because each update to i must be reflected in the shared value for i before the update to j occurs. It is possible, however, that any given invocation of method two might observe a value for j that is much greater than the value observed for i, because method one might be executed many times between the moment when method two fetches the value of i and the moment when method two fetches the value of j.
I am really confused by the above citation because it says two contradictory statements:
The shared value for j
is never greater than that for i
.
(emphasis mine).
Value for j
that is much greater than the value observed for i
.
The first statement makes sense to me because if we combine the program order rule(i++
happening before j++
) and the memory visibility guarantee of volatile (happens-before) I can sort of see why the value of j
can't exceed i
. But I an unable to see how the value of j
can can far exceed i
.
Can you please help me understand this part.
The actual value of j
can never be greater than the actual value of i
at any given moment. But when the statement
System.out.println("i=" + i + " j=" + j);
is executed, i
and j
are not evaluated at the same moment. j
is evaluated after i
is. When i
is evaluated, j
is smaller or equal to i
. But by the time j
is evaluated, the other thread might have called the method one()
many times, and both i
and j
might thus have been incremented many times. So j
is still <= i
, but what is printed could be
i=4 j=257
because it is in fact
at time t0, i=4
at time t1, j=257