2015-07-26 3 views
2

Я столкнулся с следующим примером в книге «Java Concurrency in Practice».Проблема видимости в 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; 
    } 
} 

Сво заявил далее, как:

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

Я могу понять проблему переупорядочения, но я не могу понять проблему видимости. Почему значение ready никогда не станет видимым для чтения? Как только основной поток записывает значение в ready, рано или поздно читательский поток получит свой шанс запустить, и он сможет читать значение ready. Почему изменения, сделанные основным потоком в ready, могут быть не видны нити читателя?

+1

Дубликат http://stackoverflow.com/questions/15322527/how-do-visibility-problems-occur-in-java-concurrency – racraman

+0

Спасибо за ссылку. – Mandroid

+1

Возможный дубликат [вопрос о примере Java Concurrency in Practice] (http://stackoverflow.com/questions/1919469/question-about-java-concurrency-in-practice-example) –

ответ

1

метод никогда не сможет увидеть последнее значение ready, поскольку он может принимать и оптимизировать, что значение не изменится за пределами его потока. Это предположение можно отнять, используя соответствующие функции параллелизма языка, такие как добавление ключевого слова volatile к объявлению ready.

1

Я считаю, что это новая проблема, которая началась с многоядерных процессоров и отдельных кэшей процессора.

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

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