2010-05-14 3 views
43

Что такое использование ConcurrentHashMap в Java? Каковы его преимущества? Как это работает? Пример кода тоже полезен.ConcurrentHashMap в Java?

+0

http://javarevisited.blogspot.in/2013/02/concurrenthashmap-in-java-example-tutorial-working.html – roottraveller

ответ

58

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

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

ConcurrentHashMap<String, Integer> myMap = new ConcurrentHashMap<String, Integer>(); 

// some stuff 

if (!myMap.contains("key")) { 
    myMap.put("key", 3); 
} 

Этот код не THREADSAFE, потому что другой поток может добавить отображение для "key" между вызовом contains и призыв к put. Правильная реализация будет:

myMap.putIfAbsent("key", 3); 
+4

Я бы описал это скорее как «безопасно несинхронизированный». Это позволяет двум потокам быть в то же время и одновременно обещать закончить в последовательном состоянии. – Affe

+4

Синхронизация не является (внешней) гарантией заказа. – danben

+4

Это не гарантия того, что потоки, запрашивающие монитор, получат его в запрошенном порядке, но прежде чем гарантировать, что когда один поток обретает монитор и начинает изменять карту, никто другой не увидит его, пока модификация не будет сделанный. В параллельной карте один поток может начать ставить, а затем не планировать снова в течение долгого времени, а другие потоки могут выполнять запросы, которые не будут отображаться. – Affe

11

Действительно большая функциональная разница в том, что не бросает исключение, и/или в конечном итоге коррумпированный, когда кто-то изменяет его в то время как вы используете его.

С регулярными коллекциями, если другой поток добавляет или удаляет элемент во время доступа к нему (через итератор), он генерирует исключение. ConcurrentHashMap позволяет им вносить изменения и не останавливает поток.

Имейте в виду, что он не гарантирует каких-либо гарантий синхронизации или обещаний о видимости момента времени от одного потока к другому. (Это похоже на изоляцию данных с защитой от чтения, а не на синхронизированную карту, которая больше похожа на сериализуемую изоляцию базы данных. (Old school row-locking SQL serializable, а не Oracle-ish multiversion serializable :))

общее использование, которое я знаю, заключается в кешировании неизменяемой производной информации в средах App Server, где многие потоки могут обращаться к одной и той же вещи, и не имеет большого значения, если два из них будут вычислять одно и то же значение кеша и помещать его дважды, потому что они чередуются и т. д. (например, он широко используется внутри среды Spring WebMVC для хранения конфигурации, связанной с исполняемой средой, например сопоставлений с URL-адресами для методов Handler.)

+1

Это совсем не так. Javadocs явно указывает, что все операции являются потокобезопасными. – danben

+0

Все операции являются потокобезопасными, но до обеда не происходит, как в случае с синхронизированной картой. То, что вы видите, когда вы смотрите в ConcurrentHashMap, является результатом последних завершенных операций. Некоторые из них, возможно, начались значительно позже, чем когда вы начали искать. Он работает скорее как изоляция базы данных с чтением, тогда как синхронизированная карта больше похожа на сериализуемую изоляцию базы данных. – Affe

+0

отличный ответ – SuprF1y

22

ConcurrentHashMap Позволяет осуществлять параллельный доступ к карте. HashTables также предлагает синхронизированный доступ к карте, но вся ваша карта заблокирована для выполнения любой операции.

Логика для ConcurrentHashMap заключается в том, что your entire table is not getting locked, но только часть [segments]. Каждый сегмент управляет собственным HashTable. Блокировка применяется только для обновлений. В случае извлечения, он позволяет полностью параллелизм.

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

enter image description here

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

public ConcurrentHashMap(int initialCapacity, 
         float loadFactor, int concurrencyLevel) 

Как заявил другой ответ, то ConcurrentHashMap предлагает новый метод putIfAbsent(), который похож поставить кроме значения не будет отменен, если ключ существует.

private static Map<String,String> aMap =new ConcurrentHashMap<String,String>(); 

if(!aMap.contains("key")) 
    aMap.put("key","value"); 

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

+0

по умолчанию размер 32, тогда как 4 потока могут создать сегмент размера 16. не было бы 8 –

2

Он может быть использован для запоминания:

import java.util.concurrent.ConcurrentHashMap; 
public static Function<Integer, Integer> fib = (n) -> { 
    Map<Integer, Integer> cache = new ConcurrentHashMap<>(); 
    if (n == 0 || n == 1) return n; 
    return cache.computeIfAbsent(n, (key) -> HelloWorld.fib.apply(n - 2) + HelloWorld.fib.apply(n - 1)); 
}; 
0

1.ConcurrentHashMap потокобезопасен что код можно получить с помощью одного потока одновременно.

2.ConcurrentHashMap синхронизирует или блокирует определенную часть Карты. Чтобы оптимизировать производительность ConcurrentHashMap, карта делится на разные разделы в зависимости от уровня параллелизма. Так что нам не нужно синхронизировать весь объект Map.

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

4.ConcurrentHashMap не допускает значений NULL. Таким образом, ключ не может быть пустым в ConcurrentHashMap.

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