#java #многопоточность #jvm
Добрый день. Есть небольшой вопрос по JMM. Я знаю как работает happens-before, но не могу понять один момент. Вот код: private static int x = 0; private static volatile boolean flag = false; public static void main(String[] args) throws InterruptedException { new Thread(() -> { x = 10; while (!flag) ; System.out.println(x); }).start(); x = 5; flag = true; } Какое значение должно принять X? Если какое-то правило чтобы определить это?
Ответы
Ответ 1
Если изобразить потоки выполнения в вашем коде, мы получим такую картину: Main thread - это основной поток вашей программы, Thread1 - поток, который вы явно создаете. Запись и чтение волатильной переменной flag действительно создают отношение Happens-Before (E → B на диаграмме). Таким образом по отношению к вызову System.out.println(x); у нас есть два потока выполнения, для каждого из которых гарантируется порядок выполнения: A → B → C и D → E → B → C. Запись в переменную x произойдет гарантированно раньше ее чтения. Но вот инструкции записи в переменную x (A и D) находятся в состоянии гонки (race condition) и их порядок выполнения друг относительно друга не определен. В итоге то, что мы видим на диаграмме никак нельзя назвать полным порядком. JVM вполне может выполнить инструкции следующим образом:Ответ 2
Мы не знаем какое значение увидит инструкция System.out.println(x); по нескольким причинам: Поток может прочитать значение, установленное в нем (независимо было ли оно установлено раньше или позже другого потока) или значение, установленное в другом потоке. В виду того что гарантии на то, какое значение прочитает поток не даются. В виду того, что невозможно определить время выполнения инструкции в различных поток относительно других потоков - неизвестно в какой момент потоки выполнят инструкции x = 10 и flag = true относительно друг друга. Относительно happens-before происходящего с volatile переменной. В данном случае если чтение volatile переменной происходит после записи ее переменной, то операция чтения ОБЯЗАТЕЛЬНО будет видеть "новые" данные. В данном случае нам это говорит лишь о том, что поток который находится в цикле выйдет из него, как только будет выполнена инструкция flag = true. Но опять же о том, когда будет выполнена инструкция flag = true нам неизвестно, она может быть выполнена как до, так и после чтения (одного или нескольких) значения из volatile переменной в порожденном потоке. Необходимо отметить, что отношение, изображенное на картинке в ответе Nofate не должно трактоваться, как обязательный порядок индукцией или блокировка читателя до момента пока не будет установлено значение volatile переменной. “Запись в переменную x произойдет гарантированно раньше ее чтения.” Поток просто будет находится в бесконечном цикле до момента выполнения flag = true.
Комментариев нет:
Отправить комментарий