并发集合
Java 提供了线程安全的并发集合类,用于替代传统的集合类在多线程环境中的使用。
1. ConcurrentHashMap
线程安全的 HashMap,采用分段锁(JDK 7)或 CAS + synchronized(JDK 8+)实现。
1.1 基本用法
java
import java.util.concurrent.*;
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 基本操作
map.put("key", 1);
Integer value = map.get("key");
map.remove("key");1.2 原子操作
java
// putIfAbsent:不存在才放入
map.putIfAbsent("key", 2);
// computeIfAbsent:不存在才计算并放入
map.computeIfAbsent("key2", k -> expensiveComputation(k));
// computeIfPresent:存在才计算并更新
map.computeIfPresent("key", (k, v) -> v + 1);
// merge:合并值
map.merge("key", 5, Integer::sum);
// getOrDefault:不存在返回默认值
int val = map.getOrDefault("key", 0);1.3 与 Hashtable 对比
| 特性 | ConcurrentHashMap | Hashtable |
|---|---|---|
| 锁粒度 | 分段锁/CAS | 整个表加锁 |
| 性能 | 高 | 低 |
| 允许 null key/value | ❌ | ❌ |
| 迭代器 | 弱一致性 | 快速失败 |
1.4 适用场景
- 高并发读写的缓存
- 计数器
- 共享配置
java
// 统计访问次数
ConcurrentHashMap<String, AtomicLong> counter = new ConcurrentHashMap<>();
public void recordAccess(String url) {
counter.computeIfAbsent(url, k -> new AtomicLong(0))
.incrementAndGet();
}2. CopyOnWriteArrayList
适合读多写少的场景,写时复制整个数组。
2.1 基本用法
java
import java.util.concurrent.*;
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("item1");
list.add("item2");
// 遍历时修改不会抛出 ConcurrentModificationException
for (String item : list) {
if (item.equals("item1")) {
list.add("item3"); // 安全操作
}
}2.2 工作原理
写操作:
┌─────────────────┐ 复制 ┌─────────────────┐
│ 原始数组 [A,B,C]│ ───────────► │ 新数组 [A,B,C,D]│
└─────────────────┘ └─────────────────┘
│
▼
引用指向新数组
读操作:
直接读取当前数组,无需加锁2.3 适用场景
- 监听器列表
- 配置项列表
- 黑白名单
⚠️ 注意:写操作开销大,不适合频繁写入的场景。
3. CopyOnWriteArraySet
基于 CopyOnWriteArrayList 实现的 Set。
java
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
set.add("a");
set.add("b");
set.add("a"); // 不会重复添加4. BlockingQueue
阻塞队列,常用于生产者-消费者模式。
4.1 常见实现
| 实现类 | 特点 |
|---|---|
ArrayBlockingQueue | 有界数组队列 |
LinkedBlockingQueue | 可选有界链表队列 |
PriorityBlockingQueue | 优先级队列 |
SynchronousQueue | 不存储元素的队列 |
DelayQueue | 延迟队列 |
4.2 核心方法
| 操作 | 抛异常 | 返回特殊值 | 阻塞 | 超时 |
|---|---|---|---|---|
| 插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
| 移除 | remove() | poll() | take() | poll(time,unit) |
| 检查 | element() | peek() | - | - |
4.3 生产者-消费者示例
java
import java.util.concurrent.*;
public class ProducerConsumerDemo {
public static void main(String[] args) {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
// 生产者
new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
queue.put("消息" + i); // 队列满时阻塞
System.out.println("生产: 消息" + i);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 消费者
new Thread(() -> {
try {
while (true) {
String msg = queue.take(); // 队列空时阻塞
System.out.println("消费: " + msg);
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}5. ConcurrentLinkedQueue
无锁的线程安全队列,基于 CAS 实现。
java
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.offer("a");
queue.offer("b");
String head = queue.poll();适用场景
- 高并发无界队列
- 不需要阻塞操作
6. ConcurrentSkipListMap
线程安全的有序 Map,基于跳表实现。
java
ConcurrentSkipListMap<String, Integer> map = new ConcurrentSkipListMap<>();
map.put("apple", 1);
map.put("banana", 2);
map.put("cherry", 3);
// 有序遍历
map.forEach((k, v) -> System.out.println(k + ": " + v));
// 范围查询
SortedMap<String, Integer> subMap = map.subMap("apple", "cherry");7. 集合类选择指南
| 场景 | 推荐类 |
|---|---|
| 高并发读写 Map | ConcurrentHashMap |
| 有序并发 Map | ConcurrentSkipListMap |
| 读多写少 List | CopyOnWriteArrayList |
| 生产者消费者 | BlockingQueue |
| 高并发无界队列 | ConcurrentLinkedQueue |
性能对比
并发读写性能(从高到低):
ConcurrentHashMap
▼
ConcurrentSkipListMap
▼
Collections.synchronizedMap()
▼
Hashtable