Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't understand example of volatile in Java specification

I got general understanding what volatile means in Java. But reading Java SE Specification 8.3.1.4 I have a problem understanding the text beneath that certain volatile example.

class Test {
    static volatile int i = 0, j = 0;
    static void one() { i++; j++; }
    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }
}

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.

How is

j never greater than i

, but at the same time

any given invocation of method two might observe a value for j that is much greater than the value observed for i

??

Looks like contradiction.

I got j greater than i after running sample program. Why use volatile then? It gives almost the same result without volatile (also i can be greater than j, one of previous examples in specs). Why is this example here as an alternative to synchronized?

like image 723
humme1 Avatar asked Dec 07 '16 20:12

humme1


2 Answers

At any one time, then j is not greater than i.

This is different from what method two observes because it is accessing the variables i and j at different times. i is accessed first, and then j is accessed slightly later.

This isn't a direct alternative to the synchronized version because the behavior is different. One difference from not using volatile is that without volatile, values of 0 could always be printed. The increment doesn't ever need to be visible.

The example demonstrates the ordering of volatile accesses. An example that requires this could be something like:

volatile boolean flag = false;
volatile int value;

// Thread 1
if(!flag) {
    value = ...;
    flag = true;
}

// Thread 2
if(flag) {
    System.out.println(value);
    flag = false;
}

and thread 2 reads the value that thread 1 set rather than an old value.

like image 70
fgb Avatar answered Sep 20 '22 22:09

fgb


I'd like to propose that it's a mistake and the examples were supposed to print j before i:

static void two() {
    System.out.println("j=" + j + " i=" + i);
}

The novelty in the first example is that, due to update reordering, j can be greater than i even when observed first.

The final example now makes perfect sense with some minor edits to the explanation (edits and commentary in brackets):

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 [observed to be] 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 [i] that is much greater than the value observed for [j], because method one might be executed many times between the moment when method two fetches the value of [j] and the moment when method two fetches the value of [i].

The key point here is that the second update will never be observed before the first update, when using volatile. The last sentence about the gap between the two reads is entirely parenthetical, and i and j were swapped to conform to the erroneous example.

like image 31
shmosel Avatar answered Sep 22 '22 22:09

shmosel