← [ BACK_TO_NOTES ]

Java 并发集合

并发集合解决什么、不解决什么:ConcurrentHashMap、阻塞队列与写时复制结构的选型。

#concept #growing #dev #java

[!info] related notes

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

结合场景再看三个关注点

  1. 用 merge/compute 而不是 get+put。
  2. ConcurrentHashMap 的迭代弱一致,不保证整个映射的快照;CopyOnWriteArrayList 的迭代器则固定于创建时的数组快照。\
  3. BlockingQueue 适合作生产者-消费者通道。

核心概念与准确模型

1. ConcurrentHashMap

  • 以每个键的原子操作与 API 可见性保证推理;分段/桶级同步是随 JDK 演进的实现细节。
  • compute/merge 的回调应短小,避免慢 I/O 或递归修改该映射;存入的可变对象不会自动变成线程安全。\
  • 禁止 null 键值(与 HashMap 不同)

2. BlockingQueue

  • put/take 必要时等待;offer 返回是否入队,add 在有界队列满时抛异常;限时 offer 可实现有界等待。
  • 接口本身没有通用 close,消费者退出需中断、结束标记或其他协议。\
  • 线程池工作队列常用

3. CopyOnWriteArrayList

  • 读多写少
  • 写拷贝成本高;快照迭代器不支持 remove/set/add,也看不到创建后的修改。\

边界情况与反直觉行为

  1. size/isEmpty 等只能作为并发变化中的观察,不应据此完成“检查后执行”的业务控制;putAll 等批量操作也未必整体原子。\
  2. 复合业务校验库存仍要领域层原子性/DB 约束。
  3. 并发集合 ≠ 免锁设计完成。

常见误区

[!warning] 常见误区:ConcurrentHashMap 包治百病 它不替代事务与跨键不变量。

工程实践

  1. 优先原子复合 API。
  2. 队列设定容量实现背压。
  3. 读多写少结构先测量。
  4. 与数据库约束一起设计正确性。

本节总结

  • 并发容器保单操作安全
  • 复合操作要用原子 API
  • 选型看读写模式

自测题

  1. 为什么 CHM 不支持 null?
  2. BlockingQueue 如何形成背压?
参考答案
  1. null 与“不存在”语义混淆,并发下更难解释。
  2. 满时 put 等待,offer 可返回 false 或限时等待;调用方必须实际阻塞、限流或处理拒绝,单有一个有界队列不会自动完成背压设计。

延伸阅读与资料来源

资料类型支撑内容
ConcurrentHashMapAPI语义
BlockingQueueAPI阻塞队列
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本