2015-07-23 5 views

ответ

10

Ну, ConcurrentHashMap был полностью переписан одновременно функции. До Java 8 каждый ConcurrentHashMap имел «уровень параллелизма», который был зафиксирован во время построения. По соображениям совместимости все еще есть constructor accepting such a level, хотя и не использует его оригинальным способом. Карта была разделена на столько сегментов, сколько уровень параллелизма, каждый из которых имеет свой собственный замок, поэтому теоретически может существовать до уровень параллелизма одновременных обновлений, если все они были нацелены на разные сегменты, что зависит от хеширование.

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

Кроме того, ConcurrentHashMap использует общие улучшения хэша, применяемые ко всем типам хэш-карт. Когда есть хеш-коллизии для определенного ведра, реализация будет прибегать к сортированной карте, такой как структура внутри этого ведра, таким образом, ухудшая сложность O(log(n)), а не сложность старой реализации при поиске в ковше O(n).

+0

Hi Holger, ** В Java 8 каждый хэш-ведро может обновляться индивидуально ** В соответствии с вашим ответом, в java 8, он блокирует только одно ведро при обновлении, а не сегменте (сборке ковшей). Но это то же самое, что и в старой версии java. Мы могли бы достичь этого, передав уровень параллелизма, равный текущей емкости. Это означает, что мы можем указать 16 потоков для 16 ведер. Тогда в чем же разница? Я знаю, что в моем понимании есть некоторый пробел. Пожалуйста, поправьте меня. –

+1

@ Pradeep Singh: не совсем. Проблема в том, что это зависит от хэш-кода реального ключа, в котором сегмент будет сохранен. Нет гарантии, что сохранение * n * ключей на карте с сегментами * n * будет иметь по одному ключу на сегмент, по сути, более высокий * n * будет тем более маловероятным, что станет идеальным дистрибутивом. Кроме того, емкость не постоянна, а количество сегментов. Поэтому, если вы инициализируете Java 7 'ConcurrentHashMap' с подсчетом сегмента, отражающим максимальную емкость карты, которую вы когда-либо имели, вы получите гигантские накладные расходы, возможно, никогда не использовавшиеся. – Holger

+0

Спасибо Хольгер. Я понял. :) –

-1

Я думаю, что есть несколько изменений по сравнению с JDK7:

  • Ленивая инициализация: в JDK8, память, используемая для каждого сегмента выделяется только тогда, когда какой-то объект добавляется к карте. В JDK7 это делается при создании карты.
  • Некоторые новые функции добавляются в JDK8, например, для каждого, уменьшить, искать и т. Д.
  • Изменение внутренней структуры: TreeBin (красно-черное дерево) используется в jdk8 для улучшения эффективности поиска.