2016-04-27 4 views
1

После прочтения JLS и глядя через несколько сценариев я не могу получить совершенно прав, какие правила делает модели памяти Java подчиняется внутрирегиональной резьбовыми семантикиJava в нити переназначения инструкции по одной и той же переменной

Рассмотрим этот код просто например цели:

public class CharIndexer { 
    public Map<char, int> charLastIndex; 

    public void changeCount(String phrase) { 
     Map<char, int> newCharLastIndex = new HashMap<char, int>(); 

     for (int i = 0; i < s.length(); i++){ 
      newCharLastIndex.put(s.charAt(i),i); 
     } 

     charLastIndex = newCharLastIndex; 
    } 
} 

в сценарии с несколькими потоками держит ссылку на тот же экземпляр CharIndexer, чтение поля charLastIndex в то время как один из них вызывает метод ChangeCount.

Было бы правильным переупорядочить, было ли задание для поля charLastIndex, последнего назначения метода, перед блоком for?

Это позволило бы потокам чтения увидеть карту, которая еще не была заполнена.

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

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

public class CharIndexer { 
    public Map<char, int> charLastIndex; 

    public void changeCount(String phrase) { 
     Map<char, int> newCharLastIndex = new HashMap<char, int>(); 

     for (int i = 0; i < s.length(); i++){ 
      newCharLastIndex.put(s.charAt(i),i); 
     } 

     // just changing values around 
     foreach(Map.Entry<char,int> charEntry : newCharLastIndex) { 
      charEntry.setValue(charEntry.getValue() * 10); 
     } 

     charLastIndex = newCharLastIndex; 
    } 
} 

Я пытаясь окутать голову, насколько далеко идет JIT-анализ, или если я не знаю конкретного набора правил для семантики внутри потока.

+0

BTW, "intra-thread" означает в пределах одного потока. Переупорядочение внутри одного потока всегда является «порядком программирования» на Java. Другими словами, вы никогда не увидите переупорядочения, видимого в пределах одного потока. – markspace

ответ

1

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

Лучший способ объяснить это, что ваш объект HashMap и ваш объект CharIndexer могут быть расположены в разных частях компьютерной памяти.

На сервере с несколькими процессорами доступ к памяти кэшируется независимо каждым процессором, поэтому, когда CPU # 1 запускает метод changeCount(), все его действия выполняются в кэше ЦП 1.

В конце концов, этот кеш покраснел в основную ОЗУ, и другие ЦП могут увидеть его, как только они перезагрузили их кеш из основной ОЗУ.

Но секция кеша, содержащая HashMap, и секция кэша, содержащая CharIndexer, может не обновляться и перезагружаться одновременно. Таким образом, CPU # 2 может увидеть обновление до CharIndexerдо видит обновление для ссылки HashMap.

Вот почему вы должны убедиться, что здание HashMapпроисходит, прежде, чем присвоение значения charLastIndex, или что оба произойдет, прежде, чем любое использование значения charLastIndex.

+0

Насколько я понимаю, нет никаких гарантий, что CPU # 2 видит эффекты CPU # 1 на 'CharIndexer'. Что мне не хватает, так как можно переопределить назначение charLastIndex, но не два для блоков во втором фрагменте кода. @Andreas Что в игре, чтобы сделать один действительный, но другой недействительным? – JRAcabado

+0

Не понимаю вас. Как вы считаете действительным и недействительным? Оба примера кода могут вести себя непредсказуемо, если «charLastIndex» получает доступ к другим потокам без синхронизации или происходит до границ. – Andreas