2013-02-27 2 views
4

Я проходил через ConcurrentHashMap и this related tutorial и имел некоторые вопросы.Что касается внутренней работы параллельного hashmap

  1. В статье было упоминание, что ConcurrentHashMap позволяет нескольким читателям читать одновременно без блокировки. Это достигается путем разбиения карты на разные части на основе уровня параллелизма и блокировки только части Карты во время обновлений. Уровень параллелизма по умолчанию - 16, и, соответственно, карта разделена на 16 частей, и каждая часть управляется с помощью другой блокировки. Это означает, что 16 потоков могут работать на карте одновременно, пока они не будут работать на разных частях Карты. Это делает ConcurrentHashMap высокой производительностью, несмотря на то, что она не повреждена. Хотя, он приходит с оговоркой: Поскольку обновление операции, как put(), remove(), putAll() или clear() не синхронизированы, одновременно поиска может не отражать самых последних изменений на карте

  2. Еще один момент, также упоминается в статье: Другой важный момент для запоминания - итерация над CHM, Iterator, возвращаемая keySet, слабо согласованы и отражены в состоянии ConcurrentHashMap и могут не отражать в последнее время изменения..

Я не понял пункты, выделенные жирным шрифтом, не могли бы вы предоставить дополнительную информацию или показать мне в простой программе?

+0

Это дает ответы на свой 1-й вопрос: http://stackoverflow.com/questions/14947723/is-concurrenthashmap-totally-safe/14947818#14947818 –

ответ

0

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

Один поток читает для пользователя1. Один поток пишет для user2. Ни одна нить не может предсказать, где в их соответствующих процессах будет выполняться другой поток. Кроме того, мы не можем предсказывать пользователям любые заказы на завершение этих двух процессов. Если запись сначала обновляет данные, чтение покажет обновленное состояние, даже если пользователь1 мог запросить чтение немного раньше.

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

Итак, когда вы разрешаете параллелизм в этих структурах данных, вы получаете тест «достаточно близко» с точки зрения времени. (Это очень похоже на те же соображения с базами данных, за исключением того, что мы привыкли думать о базах данных таким образом, а временные рамки - это несколько факторов из 10 разных.

ПРИМЕЧАНИЕ. Чтобы сделать комментарий о прекрасной временной шкале, показанной @Matts в другом ответе ...

Временная шкала показывает два потока и начало и конец для каждого потока. Запуск для двух потоков может происходить в любом порядке (a, b) или (b, a). Если вы начинаете сначала и заканчиваете сначала, сначала начинается и заканчивается сначала, а b заканчивается первым, b начинается с первого и заканчивается a сначала заканчивается, b начинается первым, а b заканчивается первым) Теперь ... представьте себе 20 потоков, которые делают одно и то же в ответ на, скажем, 20 конечных пользователей отправляют запросы на это и то. Сколько возможных способов это может сработать.

+0

пожалуйста, вы можете также покажите небольшую программу, которая сделает понимание более ясным. – user2094103

+0

Не совсем. Эта проблема возникает только иногда и только тогда, когда вещи происходят примерно в то же время из разных потоков. Вы не можете запрограммировать это, потому что он будет зависеть от скорости процессора и количества процессоров, доступных JVM, запускающих код. –

+1

Я должен отметить, что в прошлом я пытался писать тесты уровня низкого уровня, чтобы это произошло. В этом случае несоответствия между потоками были ошибкой. Я никогда не находил хороший способ сделать это. Иногда вы можете сделать это небольшим процентом времени, учитывая конкретную конфигурацию процессора. Затем тест состоит в повторении теста X раз и ожидании его отказа Y% времени. Как только тестовая машина поменялась на другую, она прекратится. Но даже до этого момента его не очень удовлетворительное испытание, которое больше похоже на политический опрос. –

2
  1. Поскольку обновление таких операций, как положить(), удалить(), putAll() или удалить() не синхронизирован, одновременно поиск может не отражать самых последних изменений на карте

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

        Thread 1 starts    Thread 1's call to get("a") 
           a call to get("a")    completes, returning null 
             |         | 
    Thread 1  ---------+---------------------------------+------- 
              time -----> 
    Thread 2  -----+---------------------------+----------------- 
            |       | 
          Thread 2 starts a   Thread 2's call to 
          call to put("a", 1)   put("a", 1) completes 
    

    Даже если Thread 2 put значение в карте Тема 1-х get завершено исполнение, резьба 1 «не видят» модификацию карты, и вернулся null.

  2. Еще один важный момент, чтобы помнить итерации над CHM, Итератор, возвращаемый Keyset из ConcurrentHashMap еженедельно последовательны и они отражают лишь состояние ConcurrentHashMap и определенной точки и может не отражать любые недавние изменения.

    Это аналогичная ситуация. Если Thread 1 получает Iterator от ConcurrentHashMapkeySet, а позже Thread 2 помещает новую запись на карту, нить 1 Iterator не может видеть эту запись. (Это может или не может.)

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

  • Нет связанных вопросов^_^