并发集合
并发集合位于 java.util.concurrent 包,专为多线程并发访问设计。
同步集合 vs 并发集合
| 类型 | 代表类 | 特点 | 性能 |
|---|---|---|---|
| 同步集合 | Vector、Hashtable、Collections.synchronizedXxx | 全表锁 | 低 |
| 并发集合 | ConcurrentHashMap、CopyOnWriteArrayList | 分段锁/CAS | 高 |
同步集合问题:全表一把锁,并发度低,遍历需手动加锁。
ConcurrentHashMap
JDK 7 实现
- 分段锁(Segment),默认 16 个段
- 每个段独立锁,并发度高
JDK 8+ 实现
- CAS + synchronized
- 锁粒度更细(桶级别)
- 读操作完全无锁
使用示例
Java
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 基本操作
map.put("张三", 25);
map.get("张三"); // 无锁读取
map.remove("张三");
// 原子复合操作
map.putIfAbsent("李四", 30); //不存在才放入
map.replace("张三", 25, 26); // 值为 25 才替换
map.compute("张三", (k, v) -> v + 1); // 计算
map.merge("张三", 1, (old, newV) -> old + newV);
// 批量操作(Java 8+)
map.forEach((k, v) -> System.out.println(k + ":" + v));
map.replaceAll((k, v) -> v * 2);
注意:ConcurrentHashMap 不允许 null 键或 null 值。
ConcurrentHashMap vs Hashtable
| 特性 | Hashtable | ConcurrentHashMap |
|---|---|---|
| 锁机制 | 全表锁 | 分段锁/CAS |
| 读操作 | 加锁 | 无锁 |
| null键值 | 不允许 | 不允许 |
| 性能 | 低 | 高 |
CopyOnWriteArrayList
特点
- 写时复制:每次写操作复制整个数组
- 读操作无锁,性能极高
- 写操作开销大,适合读多写少
使用示例
Java
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 读操作(无锁)
String s = list.get(0);
for (String item : list) {
// 遍历无需加锁
}
// 写操作(复制整个数组)
list.add("新元素");
list.remove(0);
list.set(0, "修改");
// 迭代器弱一致性:迭代期间不影响其他线程
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next()); // 即使其他线程修改,迭代继续
}
适用场景:事件监听器列表、配置列表等读多写少场景。不适合写频繁场景。
CopyOnWriteArraySet
Java
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
// 基于 CopyOnWriteArrayList 实现的去重 Set
set.add("A");
set.add("A"); // 重复不会添加
ConcurrentLinkedQueue
无界并发队列,基于 CAS 实现:
Java
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
// 入队
queue.offer("元素"); // 无界队列,不会阻塞
// 出队
String item = queue.poll(); // 空返回 null
String item = queue.peek(); // 查看队头,不移除
适用场景:高并发队列,不需要阻塞功能。
BlockingQueue 阻塞队列
ArrayBlockingQueue
有界阻塞队列(数组实现):
Java
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
// 阻塞操作
queue.put("元素"); // 队满阻塞等待
String item = queue.take(); // 队空阻塞等待
// 非阻塞操作(带超时)
boolean success = queue.offer("元素", 3, TimeUnit.SECONDS);
String item = queue.poll(3, TimeUnit.SECONDS);
LinkedBlockingQueue
可选有界阻塞队列(链表实现):
Java
// 无界(默认 Integer.MAX_VALUE)
LinkedBlockingQueue<String> unbounded = new LinkedBlockingQueue<>();
// 有界
LinkedBlockingQueue<String> bounded = new LinkedBlockingQueue<>(100);
BlockingQueue 类型
| 类型 | 特点 |
|---|---|
| ArrayBlockingQueue | 有界,数组,公平可选 |
| LinkedBlockingQueue | 可选有界,链表 |
| PriorityBlockingQueue | 无界,优先级排序 |
| DelayQueue | 无界,延迟元素 |
| SynchronousQueue | 无缓冲,直接传递 |
生产者-消费者示例
Java
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
// 生产者
new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
queue.put("item-" + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// 消费者
new Thread(() -> {
try {
while (true) {
String item = queue.take();
System.out.println("消费:" + item);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
ConcurrentSkipListMap/Set
跳表实现的并发排序集合:
Java
// 并发排序 Map
ConcurrentSkipListMap<Integer, String> map = new ConcurrentSkipListMap<>();
map.put(3, "C");
map.put(1, "A");
map.put(2, "B");
System.out.println(map); // {1=A, 2=B, 3=C}(排序)
// 并发排序 Set
ConcurrentSkipListSet<Integer> set = new ConcurrentSkipListSet<>();
set.add(3);
set.add(1);
set.add(2);
System.out.println(set); // [1, 2, 3](排序)
要点总结
- ConcurrentHashMap:分段锁/CAS,高并发 HashMap 替代
- CopyOnWriteArrayList:写时复制,读无锁,读多写少适用
- ConcurrentLinkedQueue:无界并发队列,CAS 实现
- BlockingQueue:阻塞队列,生产者-消费者模式
- ConcurrentSkipListMap/Set:并发排序集合
- ConcurrentHashMap 不允许 null 键值
- 选择原则:高并发用 ConcurrentHashMap,读多写少用 CopyOnWrite,队列用 BlockingQueue
📝 发现内容有误?点击此处直接编辑