并发集合选型:从场景出发
先问自己两个问题
拿到一个并发需求,先问:
问题 1:需要什么数据结构?
└─ Map → ConcurrentHashMap
└─ List → CopyOnWriteArrayList / ConcurrentLinkedQueue
└─ Queue/Deque → ConcurrentLinkedQueue / BlockingQueue
问题 2:读写模式是什么?
└─ 读多写少 → CopyOnWriteArrayList / CopyOnWriteArraySet
└─ 读写均衡 → ConcurrentHashMap / ConcurrentLinkedQueue
└─ 阻塞等待 → BlockingQueue(put/take)Map 类型选择
| 场景 | 推荐 |
|---|---|
| 高并发 Map | ConcurrentHashMap |
| 高并发 + 排序 Map | ConcurrentSkipListMap |
| 读多写少 Map | ConcurrentHashMap |
| 偶尔并发 | Collections.synchronizedMap(new HashMap<>()) |
java
// 高并发
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 高并发 + 排序
ConcurrentSkipListMap<String, Integer> sorted = new ConcurrentSkipListMap<>();List 类型选择
| 场景 | 推荐 |
|---|---|
| 读多写少 | CopyOnWriteArrayList |
| 高并发读写均衡 | ConcurrentLinkedQueue |
| 偶尔并发 | Collections.synchronizedList(new ArrayList<>()) |
java
// 读多写少列表
CopyOnWriteArrayList<String> readHeavy = new CopyOnWriteArrayList<>();
// 高并发列表(作为队列使用)
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();Queue 类型选择
| 场景 | 推荐 |
|---|---|
| 无界非阻塞队列 | ConcurrentLinkedQueue |
| 有界阻塞队列 | LinkedBlockingQueue |
| 同步队列(一个元素) | SynchronousQueue |
| 优先级队列 | PriorityBlockingQueue |
| 延迟队列 | DelayQueue |
java
// 无界非阻塞队列(CAS 实现)
ConcurrentLinkedQueue<Task> tasks = new ConcurrentLinkedQueue<>();
// 有界阻塞队列(生产者-消费者)
BlockingQueue<Task> bounded = new LinkedBlockingQueue<>(100);
// 同步队列(put 必须等待 take)
SynchronousQueue<Object> sync = new SynchronousQueue<>();Set 类型选择
| 场景 | 推荐 |
|---|---|
| 高并发 Set | ConcurrentHashMap.newKeySet() |
| 读多写少 Set | CopyOnWriteArraySet |
| 高并发 + 排序 Set | ConcurrentSkipListSet |
java
// 高并发 Set
Set<String> set = ConcurrentHashMap.<String>newKeySet();
// 读多写少 Set
CopyOnWriteArraySet<String> readSet = new CopyOnWriteArraySet<>();选型决策树
数据结构是什么?
│
├── Map
│ ├── 高并发 → ConcurrentHashMap
│ └── 高并发 + 排序 → ConcurrentSkipListMap
│
├── List
│ ├── 读多写少 → CopyOnWriteArrayList
│ └── 读写均衡 → ConcurrentLinkedQueue
│
├── Queue
│ ├── 非阻塞 → ConcurrentLinkedQueue
│ └── 阻塞 → BlockingQueue(按需求选择)
│ ├── 有界 → LinkedBlockingQueue
│ ├── 优先级 → PriorityBlockingQueue
│ └── 延迟 → DelayQueue
│
└── Set
├── 高并发 → ConcurrentHashMap.newKeySet()
├── 读多写少 → CopyOnWriteArraySet
└── 高并发 + 排序 → ConcurrentSkipListSet性能对比
| 集合 | 读性能 | 写性能 | 迭代安全 |
|---|---|---|---|
| ConcurrentHashMap | 极快(无锁) | 快(CAS) | Fail-Safe |
| CopyOnWriteArrayList | 极快(无锁) | 慢(复制) | Fail-Safe |
| ConcurrentLinkedQueue | 快 | 快(CAS) | Fail-Safe |
| Collections.synchronizedList | 慢(锁) | 慢(锁) | Fail-Fast |
常见误区
误区 1:用 CopyOnWriteArrayList 做高并发列表
java
// ❌ CopyOnWriteArrayList 写操作复制全量数组
// 1000 次写入 = 复制 1000 次整个数组!
CopyOnWriteArrayList<String> cow = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10000; i++) {
cow.add("item" + i); // 极慢
}
// ✅ 写多场景用 ConcurrentLinkedQueue
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();误区 2:用 BlockingQueue 做非阻塞队列
java
// ❌ BlockingQueue 的 add/put 有阻塞语义
BlockingQueue<Task> q = new LinkedBlockingQueue<>();
q.add(task); // 队列满时抛异常
// ✅ 非阻塞用 ConcurrentLinkedQueue
ConcurrentLinkedQueue<Task> queue = new ConcurrentLinkedQueue<>();
queue.offer(task); // 非阻塞总结
| 需求 | 推荐 |
|---|---|
| 高并发 Map | ConcurrentHashMap |
| 高并发 + 排序 Map | ConcurrentSkipListMap |
| 读多写少 List | CopyOnWriteArrayList |
| 高并发 List/Queue | ConcurrentLinkedQueue |
| 生产者-消费者 | BlockingQueue |
| 高并发 Set | ConcurrentHashMap.newKeySet() |
一句话:并发集合选型看两个维度——数据结构和读写模式。
