java多线程安全集合

Java 为高并发场景专门设计的高性能线程安全集合。它们各自采用了不同的并发控制策略,适用于不同的场景。下面逐一介绍它们的实现原理、特点和适用场景。

介绍:这些线程安全的并发集合分别对应以下线程不安全的集合类:

线程安全类 对应线程不安全类 说明
ConcurrentHashMap HashMap 无序键值对,高并发场景替代 HashMapHashtable
ConcurrentSkipListMap TreeMap 有序键值对(基于跳表),高并发场景替代 TreeMap
ConcurrentSkipListSet TreeSet 有序元素集(底层基于 ConcurrentSkipListMap),替代 TreeSet
CopyOnWriteArrayList ArrayList 读多写少场景替代 ArrayList,避免 ConcurrentModificationException
CopyOnWriteArraySet HashSet 读多写少场景替代 HashSet(底层使用 CopyOnWriteArrayList 实现)

1. ConcurrentHashMap

底层实现

  • JDK 1.7 :采用 分段锁(Segment) 技术,将整个 Map 分成多个 Segment,每个 Segment 独立加锁,允许多个线程同时操作不同 Segment。
  • JDK 1.8+ :取消分段锁,改用 CAS + synchronized 对节点进行更细粒度的控制。底层数据结构与 HashMap 类似(数组 + 链表 + 红黑树),写操作只锁定当前操作的桶(或树节点),读操作几乎不加锁(使用 volatile 保证可见性)。

特点

  • 高并发读写,吞吐量远高于 HashtableCollections.synchronizedMap
  • 不允许 null 键或值。
  • 提供原子性复合操作:putIfAbsent()remove()replace() 等。
  • 迭代器是 弱一致性 (不会抛出 ConcurrentModificationException,但遍历时可能不反映最新修改)。

适用场景

  • 高并发环境下的大规模 Map 操作,是 首选的并发 Map 实现

2. ConcurrentSkipListMap

底层实现

基于 跳表(Skip List) 数据结构,是一种以空间换时间的并发有序 Map。跳表通过多层索引实现近似二分查找,插入、删除、查找的平均时间复杂度为 O(log n)

特点

  • 线程安全,支持高并发读写。
  • 保持键的有序性 ,实现 ConcurrentNavigableMap 接口,提供了 subMap()headMap()tailMap() 等视图方法。
  • 并发控制采用 CAS 和锁(在跳表节点层面精细控制),性能优秀。
  • 不允许 null 键或值。

适用场景

  • 需要 有序且高并发 的 Map,例如实现并发缓存、排行榜、范围查询等。
  • TreeMap 的并发替代品。

3. ConcurrentSkipListSet

底层实现

本质上是一个 ConcurrentSkipListMap 的包装 ,所有元素作为 Map 的键,值统一为 Boolean.TRUE

特点

  • 线程安全、有序(按自然顺序或自定义 Comparator 排序)。
  • 支持高并发读写。
  • 迭代器是弱一致性。

适用场景

  • 需要 有序且高并发 的 Set,例如需要快速判断元素是否存在、保持元素有序,且允许多线程并发访问。

4. CopyOnWriteArrayList

底层实现

采用 写时复制(Copy-On-Write) 策略:

  • 内部维护一个 volatile 数组作为存储。
  • 读操作get()iterator())直接访问当前数组,不加锁,性能极高。
  • 写操作add()set()remove())先复制一份新数组,在新数组上修改,然后将数组引用指向新数组。复制过程中,读操作仍可并发访问旧数组,保证读线程不被阻塞。

特点

  • 读操作无锁,写操作因复制数组而开销较大(适合读多写少的场景)。
  • 迭代器是 快照 风格,创建后不会受后续修改影响,永远不会抛出 ConcurrentModificationException
  • 内存占用较高(写操作会临时产生两份数组)。

适用场景

  • 读远多于写 的集合,例如配置信息、监听器列表、缓存等。

5. CopyOnWriteArraySet

底层实现

直接 包装 CopyOnWriteArrayList ,所有操作委托给内部的 CopyOnWriteArrayList

特点

  • 继承 AbstractSet,元素唯一性通过内部 List 的 addIfAbsent() 保证。
  • 具备与 CopyOnWriteArrayList 相同的读写特性:读无锁、写复制。
  • 由于底层是 List,contains() 操作是 O(n) 复杂度(相对于 HashSet 的 O(1))。

适用场景

  • CopyOnWriteArrayList 类似,适用于 读多写少、且元素唯一 的场景。

对比总结

集合类 数据结构 是否有序 锁机制 读写特性 适用场景
ConcurrentHashMap 数组+链表+红黑树 无序 JDK 1.8+:CAS + synchronized 锁桶/节点 读几乎无锁,写锁粒度细 高并发通用 Map
ConcurrentSkipListMap 跳表 有序 CAS + 节点锁 读写均高效 需要有序、高并发 Map
ConcurrentSkipListSet 跳表(包装 Map) 有序 ConcurrentSkipListMap 读写均高效 需要有序、高并发 Set
CopyOnWriteArrayList 数组(写时复制) 保持插入顺序 写时复制(写锁),读无锁 读极快,写慢 读远多于写的 List
CopyOnWriteArraySet 数组(包装 List) 保持插入顺序 CopyOnWriteArrayList 读极快,写慢 读远多于写的 Set

选型建议

  • Map :默认首选 ConcurrentHashMap;若需要键有序,使用 ConcurrentSkipListMap
  • Set :若需高并发且无需排序,可考虑 ConcurrentHashMap 包装的 newKeySet()(JDK 8+,ConcurrentHashMap.newKeySet());若需有序,用 ConcurrentSkipListSet;若读远多于写且元素唯一性要求不高,可用 CopyOnWriteArraySet
  • List :若读远多于写,用 CopyOnWriteArrayList;否则可考虑用 Collections.synchronizedListConcurrentLinkedQueue 等替代(但需注意 ConcurrentLinkedQueue 不是 List 接口)。
相关推荐
悟空码字1 小时前
滑块拼图验证:SpringBoot完整实现+轨迹验证+Redis分布式方案
java·spring boot·后端
编码忘我1 小时前
java类加载器及tomcat为什么不用双亲委派
java
MegaDataFlowers2 小时前
快速上手Spring
java·后端·spring
小江的记录本2 小时前
【MyBatis-Plus】Spring Boot + MyBatis-Plus 进行各种数据库操作(附完整 CRUD 项目代码示例)
java·前端·数据库·spring boot·后端·sql·mybatis
左左右右左右摇晃2 小时前
Java 笔记--OOM产生原因以及解决方法
java·笔记
大傻^2 小时前
Spring AI Alibaba Function Calling:外部工具集成与业务函数注册
java·人工智能·后端·spring·springai·springaialibaba
逆境不可逃2 小时前
LeetCode 热题 100 之 33. 搜索旋转排序数组 153. 寻找旋转排序数组中的最小值 4. 寻找两个正序数组的中位数
java·开发语言·数据结构·算法·leetcode·职场和发展
码界奇点2 小时前
基于Spring Boot的医院药品管理系统设计与实现
java·spring boot·后端·车载系统·毕业设计·源代码管理
小旭95273 小时前
Spring MVC :从入门到精通(下)
java·后端·spring·mvc