2016-12-03 3 views
2

Я прочитал в книге, в котором говорится, что из-за оптимизации компилятора выполнение кода может быть переупорядочено, чтобы заставить ReaderThread быть в бесконечном цикле. Как это возможно?Многопоточная видимость Java?

public class NoVisibility { 
private static boolean ready; 
private static int number; 
private static class ReaderThread extends Thread { 
    public void run() { 
     while (!ready) 
      Thread.yield(); 
     System.out.println(number); 
     } 
    } 
    public static void main(String[] args) { 
     new ReaderThread().start(); 
     number = 42; 
     ready = true; 
    } 
} 
+0

Вы пробовали работать над кодом? он не идет в бесконечном цикле, когда я запускал его в Eclipse с помощью JRE-8 – AADProgramming

+0

@AADTechnical. Это ничего не доказывает. Суть в том, что JLS * позволяет * этот код приводить к бесконечному циклу. См. Мой ответ. –

+0

@AADTechnical yes Я побежал на своем настольном ПК с 5 ReaderThreads, они отлично выполнили (печать 42). Но это зависит от настройки компилятора и процессора. Это пример в книге Java Concurrency in Action. – sonnywang

ответ

4

Как это возможно?

Возможно переупорядочение кода (в общем), поскольку спецификация Java Language Specification (JLS) говорит, что это возможно. Однако переупорядочение (вероятно) не будет проблемой здесь. Скорее, бесконечный цикл, вероятно, будет связан с поведением кэша аппаратной памяти.

В этом случае нет ничего в JLS, что требует операций записи в переменных, сделанных методом main быть видимой для дочернего потока. Техническое объяснение состоит в том, что нет происходит-до цепочка, связывающая записи с (последующими) чтениями. Без критического происшествие-до цепь, видимость не гарантируется.

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

+0

спасибо, Стивен. Значит ли это, что дочерний поток проверяет копию или кеш переменной «готов», поэтому изменение основного потока не видно? или иначе невозможно, чтобы дочерний поток привел к бесконечному циклу. Просто любопытно. – sonnywang

+0

Это - одна возможность. Другое дело, что основной поток не смывает запись. И нет никакой теоретической причины, что не могло быть других объяснений на других аппаратных архитектурах. –

+0

Правильный способ понять это - думать в терминах отношений H-B. Кэш-флеши/барьеры памяти/все это просто механизмы, которые реализуют требуемое поведение в исполняющей программе на определенном оборудовании. –

-1

Возможно, это связано с кешем ЦП. ReaderThread может видеть устаревшее значение переменной «ready», поэтому он может не вырваться из цикла while. Устаревшее «готовое» значение называется устаревшими данными.

+0

почему голос? это объяснение, написанное в Java Concurrency in Action book. – sonnywang

Смежные вопросы