пример volatile (который в JLS8/8.3.1.4 volatile Fields) не работает?

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.4

Спецификация языка Java 8/8.3.1.4 volatile Fields

пример нестабильности

Вопрос:

В примере с volatile я добавляю ключевое слово synchronized к методу two(), чтобы избежать выполнения one() во время метода two().

Но я все же заметил, что j больше, чем i: почему?

Примечание.

Я использую Java HotSpot 1.8.0_112.

If you can not noticed j is larger than i, please set testVolatile()/num to a larger number.

Моя демонстрация:

public class VolatileDemo {

    static volatile int i = 0, j = 0;

    static void one() {
        i++;
        j++;
    }

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

    static void testVolatile() {
        int num = 5000;
        for (int i = 0; i < num; i++) {
            new Thread(new Runnable() {
                public void run() {
                    one();
                }
            }).start();
        }
        for (int i = 0; i < num; i++) {
            new Thread(new Runnable() {
                public void run() {
                    two();
                }
            }).start();
        }
    }

    public static void main(String[] args) {
        testVolatile();
    }
}

Мой результат:

i=4996 j=4998

i=4998 j=5000

i=4998 j=5000

....


person Zenna    schedule 12.06.2017    source источник
comment
Оба метода должны иметь ключевое слово synchronized, чтобы предотвратить одновременное выполнение.   -  person qwerty    schedule 12.06.2017
comment
Спасибо, я знаю, это один из подходов, в Java есть второй механизм, volatile fields, который для некоторых целей более удобен, чем блокировка, я просто хочу знать использование volatile.   -  person Zenna    schedule 13.06.2017


Ответы (1)


Это возможно, и это описано в ссылке, которую вы упомянули. Это в конце абзаца.

Однако возможно, что при каждом вызове второго метода может наблюдаться значение j, намного превышающее значение, наблюдаемое для i, потому что первый метод может выполняться много раз между моментом, когда второй метод получает значение i, и момент, когда второй метод получает значение j.

Таким образом, метод two() считывает i, а затем j в точном порядке, как в вашем коде. Но есть несколько вызовов метода one() между этими чтениями, которые дают результат (4998, 5000)

person Andrey Cheboksarov    schedule 12.06.2017
comment
Спасибо, я заметил это. Итак, в моем демонстрационном коде я добавил ключевое слово synchronized к методу two(), поэтому метод one() не должен выполняться во время two(); - person Zenna; 13.06.2017
comment
@Zenna, у вас есть двое, синхронизируйте их оба - person Eugene; 19.07.2017