Форум программистов, компьютерный форум, киберфорум
Java SE (J2SE)
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.63/35: Рейтинг темы: голосов - 35, средняя оценка - 4.63
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668

Как устроена ConcurrentHashMap ?

26.05.2014, 17:41. Показов 6690. Ответов 20
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Почитал про ConcurrentHashMap. Честно говоря куча вопросов.

значащие поля:
Java
1
2
3
4
5
 
    final Segment<K,V>[] segments;
    transient Set<K> keySet; 
    transient Set<Map.Entry<K,V>> entrySet; 
    transient Collection<V> values;
а что у нас было в HasMap:

Java
1
transient Entry[] table;
Что-то много всего добавили. Ведь Map.Entry и так содержит в себе и ключи и значения - зачем всё в кучу. Про сегменты пишут, что это типо как отдельные мапы...не совсем понятно.

Ну и наверное самый первый и важный вопрос - что вообще эта коллекция нам даёт то ? В HasMap в такой-то ситуации была проблема - в Concurrent реализации ее нет.

Добавлено через 1 час 4 минуты
Зачем нужны сегменты ? (знаю, что порой блокировка происходит посегментно)
По какому принципу попадают в сегменты?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.05.2014, 17:41
Ответы с готовыми решениями:

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

Как в Java устроена двоичная система?
Почему, например, двоичное 01111011 считается в Java, при переводе в десятичную как 123? Как я понял, тут и правда выходит 123, только...

Как устроена рекурсия?
Давно хотел спросить каким боком она работает? К примеру void RecFunction(int level) { if (level == 0) return; ...

20
Эксперт Java
 Аватар для KEKCoGEN
2399 / 2224 / 565
Регистрация: 28.12.2010
Сообщений: 8,672
26.05.2014, 18:29
Ответ в названии. ConcurrentHashMap поддерживает многопоточность. Отсюда и реализация. Вы можете вставить несколько элементов одновременно т.к есть сегменты.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
26.05.2014, 19:21  [ТС]
KEKCoGEN, я хотел мягко говоря более подробного ответа)

И наверное даже догадываюсь кто его сможет дать))

Добавлено через 45 минут
Цитата Сообщение от KEKCoGEN Посмотреть сообщение
ConcurrentHashMap поддерживает многопоточность
ну и он в любом случае не один такой
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
26.05.2014, 20:20
На хабре есть небольшое описание CHMv7 - http://habrahabr.ru/post/132884/
В исходниках самого CHM можно найти небольшое описание алгоритма и принципа работы.

Для CHMv8 и для CHMv7

Что касается назначения: это thread-safe универсальная мапа, скорость работы которой масштабируется на множестве потоков.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
26.05.2014, 21:49  [ТС]
turbanoff, Хабр уже читал, но там очень скупо написано.

попробую почитать исходники.

[QUOTE turbanoff]Что касается назначения: это thread-safe универсальная мапа, скорость работы которой масштабируется на множестве потоков.[/QUOTE]

Ну это да, я понял) Типо если мы просто обернем все методы syncronized, то блочим всю мапу, а тут как-то по сегментам. Но как-то такое описание меня не удовлетворяет).

В общем пока почитаю исходники)

Добавлено через 1 час 4 минуты
turbanoff, Почитал, что пишут в доке. Узнал, что эти сегменты "грузятся" по необходимости...

какого-то целостного представления так и нет(.

Java
1
static final class Segment<K,V> extends ReentrantLock implements Serializable {
а вот эта конструкция меня вообще путает. Вроде сами пишут в комменте, что Segment это HashMap, а сами наследуются от ReentrantLock. Разве тут есть отношение is-a ?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
26.05.2014, 22:29
Ну разумеется, Segment это не наследник HashMap, он просто устроен аналогичным образом.
Аналогичная таблица бакетов и поля threshold, modCount, loadFactor.

А наследником ReentrantLock-а его сделали, чтобы сэкономить на одном поле, и немного упростить код.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
26.05.2014, 23:18  [ТС]
Цитата Сообщение от turbanoff Посмотреть сообщение
А наследником ReentrantLock-а его сделали, чтобы сэкономить на одном поле, и немного упростить код.
Не знаю как насчёт библиотек, а в обычном коде выглядело бы сомнительно. Я конечно понимаю где я и где Lee, но всё-таки.

а не подскажете ссылки на буржуйском хотя бы где разжёвано как это всё работает, а то по исходникам мне как-то совсем тяжело, а те ссылки, что были упомянуты не открыли мне глаза на правду. Я просто сам по себе знаю, что если ты знаешь истину, то тебе проще отличить плохую статью от хорошей.
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
26.05.2014, 23:57
Что-то не гуглится ничего стоящего. Вот тут есть схемы, возможно с ними станет понятнее - http://javaopensourcecode.blog... shmap.html
Если читать исходники CHM, то лучше взять из java 5 - там попроще и покороче. Посмотреть можно тут
1
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
27.05.2014, 00:08  [ТС]
turbanoff, спасибо, почитаю как руки дойдут.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
27.05.2014, 18:09  [ТС]
Давайте порисуем)

вот наша до боли знакомая хэшмапа:

квадратики - бакеты
кружки объекты, которые разложены по бакетам.

сегмент это набор бакетов ?
Миниатюры
Как устроена ConcurrentHashMap ?  
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
27.05.2014, 18:35  [ТС]
ну то есть давайте от структуры данных плясать. в коде мы можем иметь указатели на всё что угодно в любых количествах, но думаю не будет проблем с пониманием, если нарисовать.

Добавлено через 12 минут
Как определяется позиция для вставки:

считаем hascode

первые 4 символа определяют сегмент. получается, что мы ограничены 9999 сегментами ?

остальные - определяют бакет.

Значит имеем, что сегменты и бакеты - жестко связаны. Если попал в сегмент1, то попадёшь в один из бакетов, который к нему относится. а может ли быть так, что бакеты пересекаются между сегментами. ну то есть может ли бакет быть вхож в 2 сегмента сразу?

Добавлено через 6 минут
Remove Entry

HashEntry is an immutable class so the next link can't be adjusted. All entries following removed node stays in the list, but all preceding ones need to be cloned.
прошу разжевать)
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
27.05.2014, 22:11
Цитата Сообщение от gredwhite Посмотреть сообщение
а может ли быть так, что бакеты пересекаются между сегментами. ну то есть может ли бакет быть вхож в 2 сегмента сразу?
Нет, ведь сегмент - это и есть набор бакетов.
Цитата Сообщение от gredwhite Посмотреть сообщение
прошу разжевать)
Когда вы делаете список, у вас в каждой ноде должен храниться указатель на следующий элемент.
Если вы делаете ноды неизменямыми, то получается что этот указатель нельзя поменять после создания ноды.
При удалении элемента из списка вам нужно поменять указатель в предыдущем элементе, но вы не можете его менять - и поэтому приходится создавать новую ноду. Так вы создали новую ноду, то в указатель, записанный в предыдущем от предыдущего, перестал был правильным - вам надо будет и его пересоздавать.
То есть при удалении приходится пересоздавать все ноды в списке, до текущего. Все последующие можно оставить так как есть, в них ничего менять не нужно.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
28.05.2014, 02:26  [ТС]
Цитата Сообщение от turbanoff Посмотреть сообщение
Когда вы делаете список, у вас в каждой ноде должен храниться указатель на следующий элемент.
Если вы делаете ноды неизменямыми, то получается что этот указатель нельзя поменять после создания ноды.
При удалении элемента из списка вам нужно поменять указатель в предыдущем элементе, но вы не можете его менять - и поэтому приходится создавать новую ноду. Так вы создали новую ноду, то в указатель, записанный в предыдущем от предыдущего, перестал был правильным - вам надо будет и его пересоздавать.
То есть при удалении приходится пересоздавать все ноды в списке, до текущего. Все последующие можно оставить так как есть, в них ничего менять не нужно.
нода == бакет?

у сегмента список бакетов. об этом речь или о чем-то другом?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
28.05.2014, 02:38
нет. Нода, это не бакет.
Сегмент состоит из массива бакетов. В бакет попадают элементы, у которых hashCode одинаковые (или почти одинаковые). Чтобы хранить такие элементы отдельный бакет представляет из себя односвязный список. Элемент этого списка - это и есть нода (HashEnty).

Сегмент - практически полный аналог обычной HashMap. Возможно стоит повторить её устройство.
1
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
28.05.2014, 10:17  [ТС]
turbanoff, ааааа всё понял) просто иногда терминология путает)

Но пересоздавание списка нод ведь нужно только при удалении ?

я думал, что новая нода всегда добавляется в конец, а получается, что скорее всего в начало списка для улучшения производительности?

А сегменты всегда имеют одинаковое количество бакетов или это как-то балансируется в зависимости от нагрузки?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
28.05.2014, 17:24
Цитата Сообщение от gredwhite Посмотреть сообщение
Но пересоздавание списка нод ведь нужно только при удалении ?
При удалении и при расширении массива HashEntry<K,V>[] table.

Цитата Сообщение от gredwhite Посмотреть сообщение
я думал, что новая нода всегда добавляется в конец, а получается, что скорее всего в начало списка для улучшения производительности?
Да, в начало:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 412:         V put(K key, int hash, V value, boolean onlyIfAbsent) {
 413:             lock();
 414:             try {
 415:                 int c = count;
 416:                 if (c++ > threshold) // ensure capacity
 417:                     rehash();
 418:                 HashEntry<K,V>[] tab = table;
 419:                 int index = hash & (tab.length - 1);
 420:                 HashEntry<K,V> first = tab[index];
 421:                 HashEntry<K,V> e = first;
 422:                 while (e != null && (e.hash != hash || !key.equals(e.key)))
 423:                     e = e.next;
 424: 
 425:                 V oldValue;
 426:                 if (e != null) {
 427:                     oldValue = e.value;
 428:                     if (!onlyIfAbsent)
 429:                         e.value = value;
 430:                 }
 431:                 else {
 432:                     oldValue = null;
 433:                     ++modCount;
 434:                     tab[index] = new HashEntry<K,V>(key, hash, first, value); //<--Вот тут создается новая нода и становится в начало списка
 435:                     count = c; // write-volatile
 436:                 }
 437:                 return oldValue;
 438:             } finally {
 439:                 unlock();
 440:             }
 441:         }
Цитата Сообщение от gredwhite Посмотреть сообщение
А сегменты всегда имеют одинаковое количество бакетов или это как-то балансируется в зависимости от нагрузки?
Вроде каждый живет своей жизнью.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
28.05.2014, 18:18  [ТС]
Цитата Сообщение от turbanoff Посмотреть сообщение
Сегмент состоит из массива бакетов
Цитата Сообщение от turbanoff Посмотреть сообщение
Чтобы хранить такие элементы отдельный бакет представляет из себя односвязный список. Элемент этого списка - это и есть нода (HashEnty).
против
Цитата Сообщение от turbanoff Посмотреть сообщение
При удалении и при расширении массива HashEntry<K,V>[] table.
так ноды хранятся в списке или массиве всё-таки?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
28.05.2014, 19:52
HashEntry<K,V>[] table - это массив односвязных списков.
Чтобы хранить ссылку на односвязный список нужно всего лишь хранить ссылку на его первый элемент. Вот в массиве и хранятся ссылки на первые элементы списков.
Каждый такой список я и называю бакетом.
0
44 / 44 / 11
Регистрация: 21.01.2013
Сообщений: 668
29.05.2014, 00:06  [ТС]
При удалении и при расширении массива HashEntry<K,V>[] table.
То есть другими словами при удалении ноды и в тех случаях, когда "нагруженность" мапы(или в данном случае сегмента?) превышает некоторое установленное значение.

Я так понимаю, что в этом случае перефигачивается(пересчитываются места куда кладутся элементы) весь сегмент(всё таки наверное не мапа)
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
29.05.2014, 14:55
Лучший ответ Сообщение было отмечено gredwhite как решение

Решение

gredwhite, Да, всё верно.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
29.05.2014, 14:55
Помогаю со студенческими работами здесь

Как устроена графика?
Я сделал программу с минимумом графики на чистом WinApi. Приведу конкретный пример: WM_PAINT: Нарисована гайка. При наведении на окно...

Как устроена корзина?
Допустим, я для корзины выделил 10 Гб. Что происходит, когда эти 10 Гб заканчиваются: нужно удалить ещё один файл FileForRECYCLER, а места...

Как устроена плавающая запятая?
Вводится число в 10-ой системе счисления и переводится в форму с плавающей запятой дробь двоичной. Помогите разобраться на примере. ...

Как устроена задержка в TTimer?
Мне необходимо несколько раз в секунду выполнять некоторую функцию, выполнение которой занимает длительное время. Предположим, что нужно...

Как устроена функция rand()
Объясните пожалуйста как работает функция rand(). Допустим нужно найти кол-во элементов равное 0 в динамическом массиве который состоит из...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! */ #include <iostream> #include <stack> #include <cctype>. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru