Страницы

Поиск по вопросам

суббота, 4 января 2020 г.

Java Memory Model и happens-before

#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.

Комментариев нет:

Отправить комментарий