ConcurrentMap та Його Реалізації
Свайпніть щоб показати меню
Приклад з реального життя
Вебзастосунок використовує ConcurrentMap для кешування часто запитуваних даних, таких як сесії користувачів. Різні потоки можуть одночасно оновлювати та читати дані з мапи, забезпечуючи швидкий доступ і безпечні операції.
Відмінності від інших типів
- Безпека у багатопотоковому середовищі:
ConcurrentMapавтоматично забезпечує синхронізацію доступу до даних, тоді як у звичайномуMapце потрібно робити вручну; - Ефективність: Дозволяє читати та записувати дані паралельно без блокування всієї структури даних.
Реалізації ConcurrentMap
ConcurrentHashMap: Ефективно підтримує декілька потоків шляхом поділу мапи на сегменти (бакети), що дозволяє паралельне виконання операцій без блокування всієї мапи.
Синтаксис
Main.java
1ConcurrentMap<Integer, Integer> concurrentHashMap = new ConcurrentHashMap<>();
ConcurrentHashMap у Java розділяє дані на кілька бакетів, кожен з яких керується окремим монітором. Така організація дозволяє різним потокам одночасно змінювати або зчитувати дані з різних бакетів, що підвищує продуктивність.
Потоки можуть паралельно отримувати доступ до бакетів, зменшуючи кількість блокувань і уникаючи гонок даних.
Кожен бакет містить записи у вигляді пар ключ-значення, які можуть бути організовані як зв'язані списки.
ConcurrentSkipListMap: Реалізація на основі skip-list, яка підтримує відсортований порядок ключів. Забезпечує швидке додавання, видалення та доступ до даних у багатопотоковому середовищі.
Синтаксис
Main.java
1ConcurrentMap<Integer, Integer> concurrentSkipListMap = new ConcurrentSkipListMap<>();
📝Вставка: При додаванні нового елемента до ConcurrentSkipListMap, він спочатку розміщується на найнижчому рівні. Далі він піднімається вгору по рівнях, поки не буде розміщений у правильному порядку за ключами та значеннями.
🔍Пошук: Для пошуку елемента за ключем ConcurrentSkipListMap починає з головного вузла найвищого рівня. Далі слідує за вказівниками, поки не знайде вузол із ключем, який дорівнює або перевищує шуканий ключ.
❌Видалення: Для видалення елемента з ConcurrentSkipListMap його спочатку видаляють з найнижчого рівня. Потім він понижується по рівнях, поки не буде видалений з місця, де його ключі та значення впорядковані правильно.
Приклад використання ConcurrentMap у коді
Основні методи
putIfAbsent(K key, V value): Додає пару ключ-значення до мапи лише якщо ключ ще не присутній.
Main.java
123ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>(); map.putIfAbsent("a", 1); // Adds the pair ("a", 1) to the map, as "a" is not already present map.putIfAbsent("a", 2); // Does not change the value, as "a" is already present in the map
remove(Object key, Object value): Видаляє пару ключ-значення, якщо ключ відповідає вказаному значенню.
Main.java
1234ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("a", 1); map.remove("a", 1); // Removes the pair ("a", 1), as "a" is mapped to value 1 map.remove("a", 2); // Does nothing, as "a" is not mapped to value 2
replace(K key, V value): Замінює запис для ключа лише якщо він наразі пов'язаний з певним значенням.
Main.java
1234ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("a", 1); map.replace("a", 2); // Replaces the value 1 with 2 for key "a" map.replace("b", 3); // Does nothing, as "b" is not present
compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction): Обчислення нового значення для вказаного ключа за допомогою заданої функції перетворення, що може включати створення нового значення, модифікацію або видалення наявного значення.
Main.java
1234ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("a", 1); map.compute("a", (k, v) -> v == null ? 1 : v + 1); // Increases the value for key "a" by 1 map.compute("b", (k, v) -> v == null ? 1 : v + 1); // Sets the value to 1 for new key "b"
merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction): Об'єднання заданого значення з наявним значенням, пов'язаним із ключем, за допомогою наданої функції перетворення, що використовується для агрегування даних.
Main.java
1234ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("a", 1); map.merge("a", 2, Integer::sum); // Sums the current value (1) with the new value (2), resulting in 3 map.merge("b", 2, Integer::sum); // Sets the value to 2 for new key "b"
getOrDefault(Object key, V defaultValue) – повернення значення, пов'язаного із зазначеним ключем, або значення за замовчуванням, якщо ключ відсутній.
Main.java
1234ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("a", 1); int value1 = map.getOrDefault("a", 0); // Returns 1, as "a" is present int value2 = map.getOrDefault("b", 0); // Returns 0, as "b" is not present
😔 Обмеження
Одним із потенційних недоліків є нестабільність порядку, оскільки деякі реалізації можуть не гарантувати порядок елементів під час ітерації. Крім того, може бути обмежена підтримка певних операцій; наприклад, атомарні умовні оновлення можуть бути не повністю підтримані в окремих реалізаціях.
💪 Переваги
З позитивного боку, висока продуктивність є ключовою перевагою, що робить цю структуру ідеальною для сценаріїв з інтенсивними операціями читання та запису. Вона також забезпечує простоту використання, значно зменшуючи потребу в ручному керуванні синхронізацією у багатопотоковому середовищі.
1. Яке призначення ConcurrentMap?
2. Яка з наведених реалізацій є потокобезпечною реалізацією ConcurrentMap?
3. Як ConcurrentHashMap забезпечує потокобезпечність?
Дякуємо за ваш відгук!
Запитати АІ
Запитати АІ
Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат