конкретный вопрос о потоке Java + синхронизация - PullRequest
0 голосов
/ 24 мая 2011

Я знаю, что этот вопрос звучит безумно, но рассмотрим следующие фрагменты Java:

Часть - I:

 class Consumer implements Runnable{
      private boolean shouldTerminate = false
      public void run() {
          while( !shouldTerminate ){
               //consume and perform some operation.
          }
      }

      public void terminate(){
        this.shouldTerminate = true;
      }
    }

Итак, первый вопрос: нужно ли мне когда-либо синхронизироваться на логическом логическом значении Terminate? Если так, то почему? Я не против пропустить флаг, установленный в true для одного или двух циклов (цикл = 1 выполнение цикла). И, во-вторых, может ли булева переменная когда-либо находиться в несовместимом состоянии (что-либо, кроме true или false)

Часть - II вопроса:

class Cache<K,V> {

  private Map<K, V> cache = new HashMap<K, V>();

  public V getValue(K key) {
     if ( !cache.containsKey(key) ) {
       synchronized(this.cache){
          V value = loadValue(key)
          cache.put(key, value);
       }  
      } 
     return cache.get(key);
  }
}

Должен ли быть синхронизирован доступ ко всей карте? Есть ли возможность, когда два потока пытаются запустить этот метод, с одним «потоком записи» в середине процесса сохранения значения в карте и одновременно «потоком чтения», вызывающим метод «содержит». Это приведет к взрыву JVM? (Я не против перезаписать значения на карте - если два потока записи пытаются загрузить одновременно)

Ответы [ 4 ]

4 голосов
/ 24 мая 2011

Оба примера кода имеют нарушенный параллелизм.

Для первого требуется хотя бы поле, помеченное volatile, иначе другой поток может никогда не увидеть изменяющуюся переменную (он может сохранить свое значение в кэше ЦП или регистре и не проверять, изменилось ли значение в памяти ).

Второй вариант еще более неработоспособен, потому что внутренние компоненты HashMap не являются поточно-ориентированными, и это не просто одно значение, а сложная структура данных - использование его из многих потоков приводит к совершенно непредсказуемым результатам. Общее правило заключается в том, что чтение и запись общего состояния должны быть синхронизированы. Вы также можете использовать ConcurrentHashMap для лучшей производительности.

2 голосов
/ 24 мая 2011

Если вы не синхронизируете переменную или не пометите переменную как volatile, нет никакой гарантии, что представление объекта в отдельных потоках когда-либо будет согласовано. Процитируем артиллерию Википедии на модели памяти Java

Основная оговорка этого заключается в том, что семантика «как будто-последовательный» не препятствует тому, чтобы разные потоки имели разные представления данных.

Реально, до тех пор, пока два потока синхронизируются в некоторые блокировки в некоторое время, будет видно обновление переменной.

Мне интересно, почему вы не хотите помечать переменную volatile?

1 голос
/ 24 мая 2011

Дело не в том, что JVM «взорвется» как таковой. Но оба случая неправильно синхронизированы, и поэтому результаты будут непредсказуемыми. Суть в том, что JVM предназначены для поведения определенным образом , если вы синхронизируете определенным образом; если вы не синхронизируете правильно, вы теряете эту гарантию.

Нередко люди думают, что нашли причину, по которой определенная синхронизация может быть опущена, или неосознанно пропускают необходимую синхронизацию, но без очевидной проблемы. Но при неадекватной синхронизации существует опасность того, что ваша программа может казаться работать нормально в одной среде, только для того, чтобы проблема появилась позже при изменении определенного фактора (например, переход на машину с большим количеством ЦП или обновление JVM, которое добавляет определенную оптимизацию).

0 голосов
/ 24 мая 2011
  1. Синхронизация shouldTerminate: см. Дилум ответ
  2. Ваше значение bool будет никогда не будь непоследовательным государством.
  3. Если один нить зовет cache.containsKey(key) время другой поток звонит cache.put(key, value) JVM будет взорвать (бросив ConcurrentModificationException) что-то плохое может случиться, если этот вызов put вызовет карту рост, но обычно будет работать (хуже, чем отказ).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...