Переменные и синхронизированные геттеры Java - PullRequest
2 голосов
/ 26 марта 2019

Я провожу некоторые эксперименты с java-параллелизмом с книгой Java "Параллелизм на практике".

У меня следующий вопрос: равен ли метод синхронизированного геттера изменчивой закрытой переменной?Некоторый код:

public class ConsoleApp {

private static boolean ready;
private static int number;



public synchronized static boolean isReady() {
    return ready;
}



private static class ReaderThread extends Thread {
    public void run() {
        while (!isReady()) {
            //Thread.yield();  // jvm updates variables on sleeping thread sometimes 
        }
        System.out.println("from class: " + number);
    }
}



public static void main ( String [] arguments ) throws InterruptedException
{
    System.out.println("start");
    Thread.sleep(3000);

    ready = false;
    number = 23;

    System.out.println("inited variable");
    Thread.sleep(3000);

    new ReaderThread().start();

    System.out.println("thread started");
    Thread.sleep(3000);

    number = 42;
    ready = true;

    System.out.println("variables changed");
    Thread.sleep(3000);


    System.out.println("ended;: " + number);
    Thread.sleep(8000);
    System.out.println("end" + number);

}
}

Этот вариант дает мне сообщение "из класса:".Например,

private static volatile boolean ready;
...
while (!ready) {
    ...
}

В чем разница с точки зрения выполнения кода?Я знаю, что «synchonized» означает «доступ к одному потоку», а volatile означает «получить значение из основного потока без кэширования»

Но почему поведение двух вариантов одинаково ??

Ответы [ 3 ]

2 голосов
/ 26 марта 2019

Только снятие и последующее получение блокировки устанавливает отношение произойдет до .Поэтому вам нужно использовать метод synchronized для получения и установки значения для переменной ready.

Но в вашем примере достаточно сделать ready volatile для установки нового значения для переменной и получения значенияиз переменной также установите произойдет до .

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

Пример в вашем вопросе всегда будет работать предсказуемо с volatile, но только с установщиком, отмеченным какsynchronized не происходит до между

ready = true;

в главном потоке и

while (!isReady()) 

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

1 голос
/ 26 марта 2019

Является ли метод синхронизированного геттера равным летучей частной переменной?

Нет.

Эквивалентность с synchronized сеттером и synchronized геттером по сравнению спеременная volatile private.

Если вы используете геттер synchronized и обычный (несинхронизированный) сеттер, между записью одного потока и чтением (последующего) другого потока не будет никаких отношений "до".переменной.

Другой момент заключается в том, что геттер и сеттер должны синхронизировать одно и то же.

Наконец, геттер или сеттер могут сделать что-то более сложное, чем чтение или запись переменной,В этом случае конструкция synchronized гарантирует, что все действия выполняются атомарно по отношению к другим потокам, синхронизирующимся с той же блокировкой.Напротив, переменная volatile не может дать вам гарантию атомарности.


Но почему поведение двух вариантов одинаково?

Вам повезло!

Модель памяти Java говорит, что при чтенииоперация гарантировано , чтобы увидеть результат предыдущей операции чтения.Если вы сделаете это правильно, ваше приложение будет работать правильно.

Обратное утверждение не так.Если вы сделаете это неправильно, вы можете получить правильное поведение в любом случае:

  • Вы всегда можете получить его на определенной платформе;например, аппаратное обеспечение с заданным количеством ядер и заданной архитектурой памяти.

  • Вы всегда можете получить его с данной версией Java.

  • Иливы можете получить правильное поведение ... за исключением редких или необычных обстоятельств.

Но нет никаких поведенческих гарантий, если вы не делаете то, что требует модель памяти Java.


Пара последствий:

  • Проверка не докажет, что ваш правильный параллельный код правильный.В лучшем случае, это может показать, что это неверно.

  • Тестирование, чтобы доказать, что неправильный параллельный код неверен, также сложно.Вы можете обнаружить, что ваш неправильный код кажется работает правильно.

1 голос
/ 26 марта 2019

Параллельность заключается в том, что вам нужно снизить свои ожидания в отношении определенности и предсказуемости. Компьютер делал это, когда вы работали однопоточно. Теперь, когда вы имеете дело с параллелизмом, это не так. Вы не можете спросить «почему это так или иначе» или «почему это так или иначе»? Все, что вы можете спросить, является ли что-то гарантировано или нет.

Две версии кода дают одинаковые результаты, когда вы пробуете его на своем компьютере, используя ваши версии ваших инструментов, потому что ничто не требует, чтобы они вели себя по-разному. Ничто не требует и того, что они будут делать то же самое. Что-то произойдет с этими кодами, и вы можете предсказать некоторые из них, а не остальные.

В любом случае, разница с синхронизированным методом или переменной volatile заключается в том, что любой доступ, чтение или запись к переменной volatile гарантированно будет выполняться так, как если бы существовала только одна основная память, а кэш локальной памяти потока не существовал. В то время как синхронизированные методы делают это только при вводе синхронизированного метода. Здесь вы выполняете синхронизацию только при чтении переменной и не выполняете надлежащей обработки при записи.

Это означает, что у вашего примера с синхронизацией было много шансов не дать ожидаемых результатов. Не то чтобы это гарантированно провалилось. Может, так и будет, а может и нет. Все, что мы можем сказать, это то, что гарантировано правильным программированием. Мы не можем сказать, что произойдет с тем, что ваши программы оставили неизвестными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...