Java集合线程安全需按场景选机制:优先用ConcurrentHashMap、CopyOnWriteArrayList等并发集合;次选Collections.synchronizedXxx(注意迭代需手动同步);复杂逻辑用synchronized块或ReentrantLock;只读场景用不可变集合。

Java 中集合类默认大多不支持多线程并发安全访问,直接在多个线程中读写 ArrayList、HashMap 等会导致数据丢失、ConcurrentModificationException 或结果不可预知。安全处理的关键不是“统一加锁”,而是按场景选对机制。
优先用 java.util.concurrent 包里的专用并发集合
这是最推荐的方式,内部已做细粒度控制,性能和安全性兼顾:
- ConcurrentHashMap:替代 HashMap,读操作无锁,写操作分段或 CAS + synchronized(JDK 8+),适合高并发读写,如缓存、计数器
- CopyOnWriteArrayList:读完全无锁,写时复制整个数组;适用于读远多于写的场景(如监听器列表、配置白名单),但写操作开销大、内存占用高、迭代期间看不到最新写入
-
BlockingQueue 实现类(如
LinkedBlockingQueue、ArrayBlockingQueue):自带阻塞与线程协调能力,天然适合生产者-消费者模型,无需额外同步 - ConcurrentSkipListMap/Set:提供排序能力的线程安全集合,适合需要有序且并发的场景
Collections.synchronizedXxx 包装器适合简单场景
它给原始集合所有方法套上 synchronized 锁(锁对象是集合自身),使用简单但粒度较粗:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 适用于并发压力不大、逻辑简单的应用,例如小规模后台任务协调
- 必须注意:迭代操作不自动同步,否则仍会抛出异常。正确写法是手动同步整个遍历块:
synchronized(list) { for (String s : list) { ... } } - 不建议用于高频复合操作(如“先检查再添加”),这类逻辑需额外加锁或改用原子方法
显式加锁适用于自定义逻辑或混合操作
当集合操作嵌套在业务逻辑中,或需保证多个集合/变量间的一致性时,应主动控制同步范围:
- 用
synchronized块包裹关键区,锁对象建议是私有 final 对象,避免锁膨胀或外部干扰 - 复杂场景可考虑
ReentrantLock,支持超时获取、可中断、公平性等高级特性 - 避免锁住整个方法或 this,防止不必要的串行化;也别锁 class 对象,易引发死锁
不可变集合适用于只读共享场景
如果集合构建后不再修改,用 ImmutableList.of()、ImmutableSet.copyOf()(Guava)或 JDK 10+ 的 List.copyOf() 等生成不可变副本:
- 天然线程安全,无同步开销
- 适合配置项、枚举列表、初始化后的元数据等静态结构
- 注意:不可变 ≠ 不可变引用,若引用被重新赋值,仍需保证可见性(如用
final或 volatile)

















