Java 并发集合
并发集合解决什么、不解决什么:ConcurrentHashMap、阻塞队列与写时复制结构的选型。
#type / concept
#status / growing
#tech / dev
#resource / java
[!info] 关联笔记
Java 并发集合
这个概念为什么出现
普通 HashMap/ArrayList 非线程安全。并发集合在特定操作上提供线程安全与更好伸缩,但并不自动保证多步业务不变量。
[!abstract] 一句话理解 并发集合让单次 API 调用在并发下安全;复合“先查后改”仍需原子方法(如
compute)或外部同步。
最小可运行示例
场景:多线程统计接口命中次数
import java.util.concurrent.ConcurrentHashMap;
public class HitCounter {
private final ConcurrentHashMap<String, Integer> hits = new ConcurrentHashMap<>();
void hit(String path) {
hits.merge(path, 1, Integer::sum); // 原子复合更新
}
int get(String path) {
return hits.getOrDefault(path, 0);
}
public static void main(String[] args) throws Exception {
HitCounter c = new HitCounter();
Thread t1 = new Thread(() -> { for (int i=0;i<1000;i++) c.hit("/a"); });
Thread t2 = new Thread(() -> { for (int i=0;i<1000;i++) c.hit("/a"); });
t1.start(); t2.start(); t1.join(); t2.join();
System.out.println(c.get("/a"));
}
}
建议运行:
javac HitCounter.java && java HitCounter
期望输出:
2000
结合场景再看三个关注点
- 用
merge/compute而不是 get+put。 - 迭代弱一致,不保证强快照。
- BlockingQueue 适合作生产者-消费者通道。
核心概念与准确模型
1. ConcurrentHashMap
- 分段/桶级并发(实现演进)
- 禁止 null 键值(与 HashMap 不同)
2. BlockingQueue
put/take阻塞- 线程池工作队列常用
3. CopyOnWriteArrayList
- 读多写少
- 写拷贝成本高
边界情况与反直觉行为
- size 等在并发下是估算/瞬时。
- 复合业务校验库存仍要领域层原子性/DB 约束。
- 并发集合 ≠ 免锁设计完成。
常见误区
[!warning] 常见误区:ConcurrentHashMap 包治百病 它不替代事务与跨键不变量。
工程实践
- 优先原子复合 API。
- 队列设定容量实现背压。
- 读多写少结构先测量。
- 与数据库约束一起设计正确性。
本节总结
- 并发容器保单操作安全
- 复合操作要用原子 API
- 选型看读写模式
自测题
- 为什么 CHM 不支持 null?
- BlockingQueue 如何形成背压?
参考答案
- null 与“不存在”语义混淆,并发下更难解释。
- 有界队列满时 put 阻塞/拒绝,减缓生产者。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| ConcurrentHashMap | API | 语义 |
| BlockingQueue | API | 阻塞队列 |