Яка різниця між ConcurrentHashMap та Collections.synchronizedMap (Map)?


607

У мене є карта, яку слід одночасно змінювати кількома потоками.

Здається, що в API Java три реалізовані синхронізовані карти Map:

  • Hashtable
  • Collections.synchronizedMap(Map)
  • ConcurrentHashMap

Як я розумію, Hashtableце стара реалізація (розширення застарілого Dictionaryкласу), яку згодом було адаптовано до Mapінтерфейсу. У той час як це буде синхронізовано, по- видимому, мають серйозні проблеми масштабованості і не рекомендуються для нових проектів.

А як щодо двох інших? Які відмінності між Картами, поверненими назад Collections.synchronizedMap(Map)та ConcurrentHashMaps? Хто підходить до якої ситуації?


7
@SmilesinaJar Посилання на даний момент розірвано, ось архівна копія цієї статті: Чому ConcurrentHashMap кращий за Hashtable і такий же хороший, як HashMap
informatik01

2
IBM: Як ConcurrentHashMap пропонує більшу конкурентоспроможність без шкоди для безпеки потоку @ ibm.com/developerworks/java/library/j-jtp08223/…
pramodc84

FYI, Java 6 запропонували ConcurrentSkipListMapще одну безпечну нитку Map. Розроблений для високоефективних навантажень, використовуючи алгоритм пропуску списку .
Василь Бурк

Відповіді:


423

Для своїх потреб використовуйте ConcurrentHashMap. Це дозволяє одночасно змінювати карту з декількох потоків без необхідності їх блокування. Collections.synchronizedMap(map)створює блокуючу карту, яка погіршить продуктивність, хоча і забезпечить узгодженість (якщо вона правильно використовується).

Використовуйте другий варіант, якщо вам потрібно забезпечити узгодженість даних, і кожен потік повинен мати оновлений перегляд карти. Використовуйте першу, якщо продуктивність є критичною, і кожен потік вставляє дані лише на карту, і читання відбувається рідше.


8
Дивлячись на вихідний код, синхронізована карта є лише реалізацією з одним mutex (блокуванням), тоді як ConcurrentHashMap є складнішим для боротьби з одночасним доступом
Vinze

123
Також врахуйте, що ConcurrentHashMap не дозволяє нульові ключі або значення. Таким чином вони НЕ є рівними альтернативами синхронізованої карти.
onejigtwojig

24
Я думаю, ви повинні прочитати це http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/
пан Спарк

5
@AbdullahShaikh Проблема, порушена в цій статті, була виправлена ​​в Java 7, а подальші вдосконалення були внесені в Java 8.
pulse0ne

5
@hengxin: як тільки ви виконуєте операцію, що складається з декількох запитів або оновлень карти, або коли ви переглядаєте карту, вам потрібно вручну синхронізувати на карті, щоб забезпечити послідовність. Синхронізовані карти гарантують послідовність лише для одиночних операцій (викликів методів) на карті, що робить її більш ніж часто нікчемною, оскільки більшість операцій з реального життя нетривіальні, тому вам доведеться в будь-якому разі синхронізувати вручну.
Холгер

241
╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║   Property    ║     HashMap       ║    Hashtable      ║  ConcurrentHashMap  ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║      Null     ║     allowed       ║              not allowed                ║
║  values/keys  ║                   ║                                         ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║ Thread-safety ║                   ║                                         ║
║   features    ║       no          ║                  yes                    ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║     Lock      ║       not         ║ locks the whole   ║ locks the portion   ║        
║  mechanism    ║    applicable     ║       map         ║                     ║ 
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║   Iterator    ║               fail-fast               ║ weakly consistent   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

Щодо механізму блокування: Hashtable блокує об'єкт , а ConcurrentHashMapблокує лише відро .


13
Hashtableне блокує частину карти. Подивіться на реалізацію. Він використовує synchronizedключ, не забезпечений блокуванням, тому він означає, що він блокується цілим hashtableу кожній операції.
Р.Мачник

6
А як щодо синхронізованої карти?
Семюель Едвін Уорд

3
Поведінка Collections.syncronizedMap подібна до резервної карти, за винятком усіх методів, захищених від потоку
Сергій Шевчик,

5
Я б надрукував таблицю і продав її за 5 доларів кожен;). Хороший @shevchyk
realPK

Відредаговано: Жоден із них не є безпечним для потоків. Це трохи вводить в оману для нових розробників. Дивіться: ibm.com/developerworks/java/library/j-jtp07233/index.html, щоб зрозуміти, що навіть ConcurrentHashMap не є повністю безпечним для потоків від зовнішніх перегонів даних. (наприклад: 1 потік видаляє значення, а інший пізніше намагається перевірити, чи він присутній, і поставити його, якщо ні. Це умова перебігу даних і все ще означає, що незважаючи на використання "ConcurrentHashMap", ви не усунуті всіх питань безпеки потоку.
Зомбі

142

"Проблеми масштабованості" для Hashtableпрограми присутні точно так само Collections.synchronizedMap(Map)- вони використовують дуже просту синхронізацію, що означає, що лише одна нитка може отримати доступ до карти одночасно.

Це не є великою проблемою, коли у вас є прості вставки та пошуки (якщо ви не робите це надзвичайно інтенсивно), але це стає великою проблемою, коли вам потрібно повторити всю карту, яка може зайняти довгий час для великої карти - поки одна нитка робить це, всі інші повинні чекати, якщо вони хочуть щось вставити чи шукати.

В ConcurrentHashMapвикористовує дуже складні методи , щоб зменшити потребу в синхронізації і дозволяють паралельний доступ для читання декількох потоків без синхронізації і, що більш важливо, забезпечує , Iteratorщо не вимагає синхронізації і навіть дозволяє мапі бути змінені під час Інтерактивного (хоча це НЕ дає ніяких гарантій чи не повертаються елементи, які були вставлені під час ітерації).


4
Тепер ось чого я хотів! :) Не синхронізований Ітератор - це лише суцільна солодкість! Танськ для інформації! :) (:
Kounavi

Чудова відповідь ... але це означає, що під час пошуку потоки не отримають останні оновлення, оскільки потоки читачів не синхронізовані.
MrA

@MrA: Ви питаєте про ConcurrentHashMap? А що ви маєте на увазі під "пошуком"?
Майкл Боргвардт

4
@Michael Borgwardt для ConcurrentHashmap, наприклад. припустимо, існує кілька потоків. деякі з них оновлюють Карту, а деякі отримують дані з тієї самої карти. Так у цьому сценарії, коли потоки намагаються прочитати, чи гарантується, що вони отримають найновіші дані, які були оновлені, оскільки потоки читачів не повинні містити блокування.
MrA

35

ConcurrentHashMap є кращим, коли ви можете ним користуватися, хоча для цього потрібен принаймні Java 5.

Він розроблений для масштабування, коли використовується декілька потоків. Продуктивність може бути дещо слабшою, коли лише один потік отримує доступ до карти за один раз, але значно кращий, коли декілька потоків отримують доступ до карти одночасно.

Я знайшов запис у блозі, який відтворює таблицю з чудової книги Java Concurrency In Practice , яку я ретельно рекомендую.

Collections.synchronizedMap має сенс справді лише в тому випадку, якщо вам потрібно обернути карту з деякими іншими характеристиками, можливо, якоюсь упорядкованою картою, як-от TreeMap.


2
Так - схоже, я згадую цю книгу в кожній іншій відповіді, яку я виголошу!
Білл Мішель

Посилання @BillMichell розірвано

@Govinda Вимкніть javascript, перш ніж отримати доступ до посилання. Запис у блозі все ще є!
Білл Мішелл

32

Основна відмінність між цими двома полягає в тому, що ConcurrentHashMapвони блокують лише частину даних, що оновлюються, тоді як інші частини даних можуть отримати доступ до інших потоків. Однак Collections.synchronizedMap()заблокує всі дані під час оновлення, інші потоки можуть отримати доступ до даних лише після звільнення блокування. Якщо є багато операцій оновлення та відносно невелика кількість операцій зчитування, слід вибрати ConcurrentHashMap.

Крім того, ще одна відмінність полягає в тому ConcurrentHashMap, що не буде збережено порядок елементів на переданій карті. Це схоже на HashMapзберігання даних. Немає гарантії збереження порядку елементів. Хоча Collections.synchronizedMap()збереже порядок елементів карти пройшло. Наприклад, якщо ви передаєте TreeMapна ConcurrentHashMapелементи замовлення в ConcurrentHashMapне може бути такою ж , як і порядок в TreeMap, але Collections.synchronizedMap()збереже порядку.

Крім того, ConcurrentHashMapможна гарантувати, що ConcurrentModificationExceptionпід час оновлення карти немає потоку, коли одна нитка оновлює карту, а інша нитка проходить ітератор, отриманий з карти. Однак Collections.synchronizedMap()не гарантується з цього приводу.

Є один пост, який демонструє відмінності цих двох, а також ConcurrentSkipListMap.


13

Синхронізована карта:

Синхронізована карта також не сильно відрізняється від Hashtable і забезпечує аналогічні показники в паралельних програмах Java. Єдина відмінність Hashtable від SynchronizedMap полягає в тому, що SynchronizedMap не є спадщиною, і ви можете обернути будь-яку карту, щоб створити її синхронізовану версію, використовуючи метод Collections.synchronizedMap ().

ConcurrentHashMap:

Клас ConcurrentHashMap забезпечує паралельну версію стандартного HashMap. Це вдосконалення функціональності синхронізованої карти, що надається в класі Collections.

На відміну від Hashtable і синхронізованої карти, вона ніколи не блокує всю карту, замість цього вона ділить карту на сегменти і блокування робиться на них. Це краще, якщо кількість потоків читачів більше, ніж кількість ниток запису.

ConcurrentHashMap за замовчуванням розділяється на 16 регіонів і блокуються. Цей номер за замовчуванням можна встановити під час ініціалізації екземпляра ConcurrentHashMap. Під час встановлення даних у певному сегменті виходить блокування для цього сегмента. Це означає, що два оновлення все ще можуть одночасно виконуватись безпечно, якщо кожне з них впливає на окремі відрізки, таким чином мінімізуючи суперечки щодо блокування та настільки максимізуючи ефективність.

ConcurrentHashMap не кидає ConcurrentModificationException

ConcurrentHashMap не кидає ConcurrentModificationException, якщо один потік намагається змінити його, а інший ітераціює над ним

Різниця між синхронізованою картою та ConcurrentHashMap

Collections.synchornizedMap (HashMap) поверне колекцію, майже еквівалентну Hashtable, де кожна операція з модифікації на карті заблокована на об’єкті Map, тоді як у випадку ConcurrentHashMap безпека потоків досягається шляхом поділу всієї карти на різні розділи на основі рівня сумісності і лише блокувати певну частину, а не блокувати всю Мапу.

ConcurrentHashMap не дозволяє нульові ключі або нульові значення, тоді як синхронізований HashMap дозволяє отримати одну нульову клавішу.

Подібні посилання

Посилання1

Посилання2

Порівняння продуктивності


12
  • Hashtableі ConcurrentHashMapне дозволяти nullключів або nullзначень.

  • Collections.synchronizedMap(Map)синхронізує всі операції ( get, put, sizeі т.д.).

  • ConcurrentHashMap підтримує повну паралельність пошуку та регульовану очікувану паралельність оновлень.

Як завжди, тут є компроміси, пов’язані із швидкістю руху - швидкісні. Вам дійсно потрібно розглянути детальні вимоги щодо сумісності вашої заявки, щоб прийняти рішення, а потім протестувати свій код, щоб перевірити, чи достатньо він хороший.


12

У ConcurrentHashMapблокуванні застосовано сегмент замість цілої карти. Кожен сегмент управляє власною внутрішньою хеш-таблицею. Блокування застосовується лише для операцій оновлення. Collections.synchronizedMap(Map)синхронізує всю карту.


чи можете ви подивіться, будь ласка, stackoverflow.com/questions/48579060/… ?
gstackoverflow

9

Ви маєте рацію, про HashTableце можете забути.

У вашій статті згадується той факт, що, хоча HashTable і синхронізований клас обгортки забезпечують основну безпеку потоку, дозволяючи одночасно отримувати доступ до карти, це не є "справжньою" безпекою потоку, оскільки для багатьох складних операцій все ще потрібна додаткова синхронізація, приклад:

synchronized (records) {
  Record rec = records.get(id);
  if (rec == null) {
      rec = new Record(id);
      records.put(id, rec);
  }
  return rec;
}

Однак не думайте, що ConcurrentHashMapце проста альтернатива для HashMapтипового synchronizedблоку, як показано вище. Прочитайте цю статтю, щоб краще зрозуміти її тонкощі.


7

Ось декілька:

1) ConcurrentHashMap блокує лише частину Map, але SynchronizedMap блокує всю MAp.
2) ConcurrentHashMap має кращі показники порівняно із SynchronizedMap та більш масштабованими.
3) У випадку з декількома читачами та однократними програмами найкращим вибором є ConcurrentHashMap.

Цей текст із різниці між ConcurrentHashMap та хештелем на Java


7

Ми можемо досягти безпеки потоку за допомогою ConcurrentHashMap та синхронізованих Hashmap та Hashtable. Але різниці є дуже багато, якщо подивитися на їх архітектуру.

  1. синхронізовані Hashmap та Hashtable

Обидва підтримуватимуть замок на рівні об'єкта. Отже, якщо ви хочете виконати будь-яку операцію, як put / get, то спочатку потрібно придбати замок. У той же час, інші потоки не дозволяють виконувати жодну операцію. Тож одночасно над цим може працювати лише одна нитка. Тож час очікування тут збільшиться. Можна сказати, що продуктивність порівняно низька при порівнянні з ConcurrentHashMap.

  1. ConcurrentHashMap

Він підтримуватиме блокування на рівні сегмента. Він має 16 сегментів і підтримує рівень сумісності як 16 за замовчуванням. Тож одночасно на ConcurrentHashMap можна працювати 16 потоків. Більше того, операція читання не потребує блокування. Таким чином, будь-яка кількість потоків може виконати операцію get на ньому.

Якщо нитка1 хоче виконати операцію поставлення в сегменті 2, а нитка2 хоче виконати операцію поставлення на сегменті 4, то це дозволено тут. Значить, 16 потоків можуть одночасно виконувати операцію оновлення (поставити / видалити) на ConcurrentHashMap.

Так що часу очікування тут буде менше. Отже, продуктивність порівняно краща, ніж синхронізована Hashmap та Hashtable.


1
, 1. що станеться, якщо кілька потоків намагаються редагувати один і той же блок? 2. Що станеться, якщо скажімо, два потоки намагаються прочитати дані з того самого блоку, де інший потік, якщо записувати дані одночасно?
prnjn

6

ConcurrentHashMap

  • Ви повинні використовувати ConcurrentHashMap, коли вам потрібна дуже велика сумісність у вашому проекті.
  • Це безпечно для потоків без синхронізації всієї карти.
  • Читання може відбуватися дуже швидко, поки запис робиться за допомогою блокування.
  • На рівні об'єкта немає блокування.
  • Блокування знаходиться на значно більш детальній деталі на рівні відра хешмапу.
  • ConcurrentHashMap не кидає ConcurrentModificationException, якщо один потік намагається змінити його, а інший ітераціює над ним.
  • ConcurrentHashMap використовує безліч замків.

SynchronizedHashMap

  • Синхронізація на рівні об'єкта.
  • Кожна операція читання / запису повинна придбати замок.
  • Блокування всієї колекції - накладні витрати.
  • Це по суті дає доступ лише до одного потоку до всієї карти та блокує всі інші потоки.
  • Це може викликати суперечки.
  • SynchronizedHashMap повертає Iterator, який невдалий при одночасній модифікації.

джерело


4

ConcurrentHashMap оптимізований для одночасного доступу.

Доступ не блокує всю карту, але використовує більш чітку стратегію, що покращує масштабованість. Існують також функціональні покращення, спеціально для паралельного доступу, наприклад, одночасні ітератори.


4

Існує одна важлива особливість, яка слід відзначити, ConcurrentHashMapокрім функції паралельності, яку вона надає, - це ідентифікатор, що не відповідає безпеці . Я бачив розробників, які використовують ConcurrentHashMapлише тому, що вони хочуть відредагувати набір записів - поставити / видалити під час ітерації над ним. Collections.synchronizedMap(Map)не забезпечує безпечний ітератор, але натомість забезпечує швидкий вихід ітератора. невдалі ітератори використовують знімок розміру карти, який не можна редагувати під час ітерації.


3
  1. Якщо узгодженість даних дуже важлива - використовуйте Hashtable або Collections.synchronizedMap (Map).
  2. Якщо швидкість / продуктивність дуже важлива і оновлення даних може бути порушено - використовуйте ConcurrentHashMap.

2

Загалом, якщо ви хочете скористатися, ConcurrentHashMapпереконайтеся, що ви готові пропустити "оновлення"
(тобто друк вмісту HashMap не гарантує, що він буде надрукувати оновлену карту) та використовувати такі API, CyclicBarrierякі забезпечують узгодженість усіх програм вашої програми життєвий цикл.


1

Метод Collections.synchronizedMap () синхронізує всі методи HashMap і ефективно зводить його до структури даних, куди одночасно може входити один потік, оскільки він блокує кожен метод у загальному блокуванні.

У ConcurrentHashMap синхронізація проводиться дещо інакше. Замість того, щоб фіксувати кожен метод на загальному блокуванні, ConcurrentHashMap використовує окремий замок для окремих відер, таким чином блокуючи лише частину карти. За замовчуванням є 16 відер, а також окремі замки для окремих відрів. Таким чином, рівень сумісності за замовчуванням становить 16. Це означає, що теоретично в будь-який момент часу 16 потоків можуть отримати доступ до ConcurrentHashMap, якщо всі вони збираються окремими відрами.


1

ConcurrentHashMap був представлений як альтернатива Hashtable в Java 1.5 як частина пакету concurrency. З ConcurrentHashMap у вас є кращий вибір не тільки, якщо він може бути безпечно використаний у паралельному багатопотоковому середовищі, але й забезпечує кращу ефективність, ніж Hashtable та синхронізована карта. ConcurrentHashMap працює краще, оскільки він блокує частину Map. Це дозволяє сумісні операції зчитування і одночасно підтримує цілісність, синхронізуючи операції запису.

Як реалізується ConcurrentHashMap

ConcurrentHashMap був розроблений як альтернатива Hashtable і підтримує всю функціональність Hashtable з додатковими можливостями, так званий рівень одночасності. ConcurrentHashMap дозволяє безліч читачів одночасно читати, не використовуючи блоки. Це стає можливим, розділяючи Map на різні частини та блокуючи лише оновлення в Map. За замовчуванням рівень одночасності становить 16, тому карта розбита на 16 частин, і кожна частина керується окремим блоком. Це означає, що 16 потоків можуть працювати з Map одночасно, якщо вони працюють з різними частинами Map. Це робить ConcurrentHashMap високим продуктивним і не знижує безпеку ниток.

Якщо вас цікавлять деякі важливі особливості ConcurrentHashMap і коли ви повинні використовувати цю реалізацію Map - я просто поклав посилання на хорошу статтю - Як використовувати ConcurrentHashMap на Java


0

Крім того, що було запропоновано, я хотів би опублікувати вихідний код, пов'язаний із цим SynchronizedMap .

Щоб зробити Mapнитку безпечною, ми можемо використовуватиCollections.synchronizedMap оператор та вводити екземпляр карти як параметр.

Реалізація synchronizedMapв Collectionsяк нижче

   public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
        return new SynchronizedMap<>(m);
    }

Як бачимо, вхідний Mapоб’єкт загортається SynchronizedMapоб'єктом.
Давайте розберемося з реалізацією SynchronizedMap,

 private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;

        private final Map<K,V> m;     // Backing Map
        final Object      mutex;        // Object on which to synchronize

        SynchronizedMap(Map<K,V> m) {
            this.m = Objects.requireNonNull(m);
            mutex = this;
        }

        SynchronizedMap(Map<K,V> m, Object mutex) {
            this.m = m;
            this.mutex = mutex;
        }

        public int size() {
            synchronized (mutex) {return m.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return m.isEmpty();}
        }
        public boolean containsKey(Object key) {
            synchronized (mutex) {return m.containsKey(key);}
        }
        public boolean containsValue(Object value) {
            synchronized (mutex) {return m.containsValue(value);}
        }
        public V get(Object key) {
            synchronized (mutex) {return m.get(key);}
        }

        public V put(K key, V value) {
            synchronized (mutex) {return m.put(key, value);}
        }
        public V remove(Object key) {
            synchronized (mutex) {return m.remove(key);}
        }
        public void putAll(Map<? extends K, ? extends V> map) {
            synchronized (mutex) {m.putAll(map);}
        }
        public void clear() {
            synchronized (mutex) {m.clear();}
        }

        private transient Set<K> keySet;
        private transient Set<Map.Entry<K,V>> entrySet;
        private transient Collection<V> values;

        public Set<K> keySet() {
            synchronized (mutex) {
                if (keySet==null)
                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
                return keySet;
            }
        }

        public Set<Map.Entry<K,V>> entrySet() {
            synchronized (mutex) {
                if (entrySet==null)
                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
                return entrySet;
            }
        }

        public Collection<V> values() {
            synchronized (mutex) {
                if (values==null)
                    values = new SynchronizedCollection<>(m.values(), mutex);
                return values;
            }
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return m.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return m.hashCode();}
        }
        public String toString() {
            synchronized (mutex) {return m.toString();}
        }

        // Override default methods in Map
        @Override
        public V getOrDefault(Object k, V defaultValue) {
            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
        }
        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            synchronized (mutex) {m.forEach(action);}
        }
        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            synchronized (mutex) {m.replaceAll(function);}
        }
        @Override
        public V putIfAbsent(K key, V value) {
            synchronized (mutex) {return m.putIfAbsent(key, value);}
        }
        @Override
        public boolean remove(Object key, Object value) {
            synchronized (mutex) {return m.remove(key, value);}
        }
        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
        }
        @Override
        public V replace(K key, V value) {
            synchronized (mutex) {return m.replace(key, value);}
        }
        @Override
        public V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
        }
        @Override
        public V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
        }
        @Override
        public V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.compute(key, remappingFunction);}
        }
        @Override
        public V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
        }

        private void writeObject(ObjectOutputStream s) throws IOException {
            synchronized (mutex) {s.defaultWriteObject();}
        }
    }

Що SynchronizedMapможна зробити узагальненим як додавання єдиного блокування до основного методу вхідного Mapоб'єкта. До всіх способів, що охороняються замком, не можна отримати доступ одночасно кількома потоками. Це означає звичайні операції, якput і getможуть виконуватись одним потоком одночасно для всіх даних Mapоб’єкта.

Це робить Map об’єктний потік безпечним зараз, але продуктивність може стати проблемою в деяких сценаріях.

ConcurrentMapЄ набагато більш складним в реалізації, ми можемо послатися на побудову кращого HashMap для деталей. У двох словах, він реалізований з урахуванням безпечності потоку та продуктивності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.