ConcurrentHashMap
HashMap的线程安全问题
并发环境下HashMap可能会导致程序死循环,原因是put操作可能会使得HashMap中的链表结构成环,导致无法找到next节点,无限循环
HashTable为什么效率低
HashMap是使用synchronized来保证县城安全的,如果并发量非常高,那么会触发synchronized锁升级机制,成为重量级锁,性能严重降低
ConcurrentHashMap是如何保证线程安全的
HashMap效率的原因是使用了同一把锁,如果有多把锁那么效率就会提高了,ConcurrentHashMap就是这么做的分段锁,ConcurrentHashMap是将数据分成一段一段的,默认情况下,ConcurrentHashMap 会创建 16 个段。然后每一段数据一把锁,当进行插入、查找或删除操作时,ConcurrentHashMap 首先根据键的哈希值计算出段的索引,然后在对应的段中进行操作。这意味着不同的键可以并发地在不同的段中进行操作,从而减少了线程之间的争用。其数据结构是由一个Segment数组和一个HashEntry数组组成的,Segment是一种KV结构的可重入锁
ConcurrentHashMap的特点
-
分段锁设计:ConcurrentHashMap 使用了分段锁的机制,将哈希表分成多个段(Segment),每个段都拥有自己的锁。这样不同的段可以并发地进行操作,从而提高了并发性能。默认情况下,ConcurrentHashMap 会创建 16 个段。
-
并发安全:由于使用了分段锁,不同段的操作可以并行执行,这使得 ConcurrentHashMap 在多线程环境下能够提供较高的并发性能,同时避免了传统 HashMap 的并发问题。
-
支持高并发读写:ConcurrentHashMap 的读操作不需要锁,可以在不阻塞其他读操作的情况下并发进行。只有写操作会锁定相应的段,以保障写操作的原子性。
-
线程安全迭代器:ConcurrentHashMap 提供了一种安全的迭代器,可以在迭代时进行并发的读操作,而不会导致 ConcurrentModificationException 异常。
-
高度可调整性:可以通过调整初始化大小、负载因子和并发级别等参数来优化 ConcurrentHashMap 的性能。
使用案例
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("one", 1);
map.put("two", 2);
map.put("three", 3);
// 并发安全地进行读操作
int result = map.getOrDefault("two", 0);
System.out.println("Result: " + result);
// 并发安全地进行写操作
map.putIfAbsent("four", 4);
// 迭代器也是并发安全的
map.forEach((key, value) -> System.out.println(key + ": " + value));
}
}