并发集合

一、ConcurrentHashMap 1.7 vs 1.8

1. JDK 1.7 :分段锁(Segment)

  • 结构:Segment 数组 + HashEntry 数组 + 链表
  • 锁设计
    • 把 Map 分成 16 个 Segment
    • 每个 Segment 是一把独立的 ReentrantLock
    • 不同 Segment 可以并发读写
  • 核心分段加锁,减小锁粒度,提高并发度
  • 缺点
    • 结构复杂
    • 链表查询慢 O (n)
    • 并发度默认 16,不够灵活

2. JDK 1.8 :CAS + synchronized

  • 结构数组 + 链表 + 红黑树
  • 锁设计
    • 不再用分段锁
    • 锁头节点:只锁住当前数组下标内的链表 / 红黑树
    • 粒度更细,并发更高
  • 查询:O (1) → O (logn),性能大幅提升

3. 1.8 put 流程

  1. 根据 key 计算 hash
  2. 数组为空? 先 CAS 初始化
  3. 对应下标位置为空?
    • 直接 CAS 写入不加锁
  4. 下标位置有数据?
    • synchronized 锁住头节点
    • 是链表:遍历插入
    • 是红黑树:树结构插入
  5. 长度超过阈值:扩容
  6. 链表长度 ≥8 且数组≥64:转红黑树

4. 总结一句话

  • 1.7:Segment 分段锁 + ReentrantLock
  • 1.8CAS 无锁写入 + synchronized 锁头节点 + 红黑树
  • 并发性能:1.8 >>> 1.7

二、为什么 1.8 用 CAS + synchronized?

  1. 无冲突时用 CAS

    不加锁,直接原子写入,速度极快

  2. 有冲突时用 synchronized 锁头节点

    锁粒度极小

  3. JDK 1.6 后 synchronized 做了大量优化

    偏向锁 → 轻量级锁 → 重量级锁

    高并发场景不输 ReentrantLock

  4. 代码更简洁、JVM 更易优化


三、CopyOnWriteArrayList / CopyOnWriteArraySet

1. 是什么?

写时复制的线程安全集合

  • 读:完全无锁,并发读极高
  • 写:复制一个新数组,写入后替换引用

2. 写时复制机制(核心)

  • 写操作(add/set/remove)

    1. lock 锁
    2. 复制原数组,生成新数组
    3. 在新数组上修改
    4. 把 array 引用指向新数组
    5. 释放锁
  • 读操作(get)

    无锁,直接读当前 array 引用

3. 特点

  • 读极快,无锁
  • 写开销大(复制数组)
  • 数据最终一致:写时不影响读,读的是旧数组

四、适用场景

ConcurrentHashMap

  • 高并发读写
  • 缓存、配置、会话存储
  • 大部分分布式缓存底层用它

CopyOnWriteArrayList

  • 读多写极少
  • 白名单、配置列表、监听器列表
  • 不能用于频繁写入(性能爆炸)

极简总结

  1. CHM 1.7:Segment 分段锁 + ReentrantLock
  2. CHM 1.8CAS + synchronized 锁头节点 + 红黑树
  3. CopyOnWrite:读无锁、写复制新数组,适合读多写少
  4. 两者都是高并发安全,性能远超 Vector、Hashtable

并发集合
http://hanqichuan.com/2026/04/16/java并发/并发集合/
作者
韩启川
发布于
2026年4月16日
许可协议