Избегает ли энергозависимая запись переменной неправильных записей?

Гарантирует ли volatile запись, что все записи (энергонезависимые / volatile записи) произойдут до того, как они в одном потоке будут видны другому потоку?

Будет ли следующий код всегда производить 90,80 как вывод?

public class MyClass
{
    private boolean flag = false;
    private volatile int volatileInt = 0;
    private int nonVolatileInt = 0;
    public void initVariables()
    {
        nonVolatileInt = 90; // non-volatile write
        volatileInt = 80; // volatile write
        flag = true; // non-volatile write
    }
    public void readVariables()
    {
        while (flag == false)
        {}
        System.out.println(nonVolatileInt + ","+ volatileInt);
    }
    public static void main(String st[])
    {
        final MyClass myClass = new MyClass();
        Thread writer = new Thread( new Runnable()
        {
            public void run()
            {
                myClass.initVariables();
            }
        });
        Thread reader = new Thread ( new Runnable()
        {
            public void run()
            {
                myClass.readVariables();
            }
        });
        reader.start();writer.start();
    }
}

Меня беспокоит метод initVariables(). Разве у JVM нет свободы переупорядочивать блоки кода следующим образом?:

flag = true;
nonVolatileInt = 90 ; 
volatileInt = 80;

И, следовательно, мы получаем вывод потока чтения как: 0,0
Или они могут быть переупорядочены следующим образом:

nonVolatieInt = 90;
flag = true;
volatileInt = 80;

И, следовательно, мы получаем вывод потока чтения как: 90,0

1 ответ

Решение

Энергозависимая запись гарантирует, что уже выполненные записи не появятся после этой записи. Однако, чтобы убедиться, что вы видите это, вам нужно сначала выполнить энергозависимое чтение.

И, следовательно, мы получаем вывод потока чтения как: 90,0

Правильный. Однако, если вы правильно выполните чтение, вы не сможете получить 0, 80

0, 0 - ok
90, 0 - ok
90, 80 - ok
0, 80 - breaks happens before.

Тем не менее, ваши чтения не гарантируют, что произойдет раньше, чем поведение, так как они не выполняют изменчивое чтение в первую очередь.

System.out.println(nonVolatileInt + ","+ volatileInt);

Сначала считываются энергонезависимые поля, поэтому вы можете увидеть старую версию энергонезависимого поля и новую версию энергозависимого поля.

Примечание: в действительности вы вряд ли увидите проблему. Это связано с тем, что кэши делают недействительной всю строку кэша за раз, и если эти поля находятся в одном и том же 64-байтовом блоке, вы не должны видеть несоответствия.

Скорее всего, проблема будет в этом цикле.

 while (flag == false)
    {}

Проблема в; JIT может видеть ваши потоки пишет в flag так что это может встроить значение. т.е. ему никогда не нужно читать значение. Это может привести к бесконечному циклу.

http://vanillajava.blogspot.co.uk/2012/01/demonstrating-when-volatile-is-required.html

Другие вопросы по тегам