arraylist线程不安全,多线程需同步:可用collections.synchronizedlist(简单但复合操作需手动锁)、copyonwritearraylist(读多写少、迭代安全)或reentrantlock手动加锁;禁用继承加synchronized方式。

Java 中的 ArrayList 本身不是线程安全的,多线程环境下直接并发读写会引发 ConcurrentModificationException 或数据不一致问题。要实现线程安全的同步列表,有几种主流且实用的方式,关键在于根据使用场景选择合适方案。
用 Collections.synchronizedList 包装
这是最简单直接的方式,底层通过在每个方法上加 synchronized 锁(锁的是 list 对象本身)来保证操作原子性:
List<string> syncList = Collections.synchronizedList(new ArrayList());
syncList.add("a");
syncList.get(0);
</string>
注意:虽然单个方法是线程安全的,但复合操作仍需手动同步。例如遍历必须显式加锁,否则可能抛异常:
synchronized (syncList) {
for (String s : syncList) { // 必须同步整个迭代过程
System.out.println(s);
}
}
用 CopyOnWriteArrayList 替代(适合读多写少)
CopyOnWriteArrayList 是 JUC 提供的线程安全列表,写操作(add、set、remove)时复制整个数组,读操作无锁、高性能:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 适用于读操作远多于写操作的场景,比如监听器列表、配置项缓存
- 写操作开销大,不适合高频修改
- 迭代器基于快照,不会抛
ConcurrentModificationException,但看不到写操作的最新结果
List<string> cowList = new CopyOnWriteArrayList();
cowList.add("x"); // 内部复制数组
System.out.println(cowList.get(0)); // 无锁读取
</string>
手动加锁(灵活控制粒度)
若需更细粒度控制(比如只对部分逻辑加锁),可用 ReentrantLock 或 synchronized 块包裹关键代码段:
- 避免锁住整个 list 对象,减少争用
- 适合复杂业务逻辑,如“检查存在再添加”这类非原子操作
- 需自行保证锁的一致性和可重入性
private final List<string> list = new ArrayList();
private final ReentrantLock lock = new ReentrantLock();
public void addIfAbsent(String item) {
lock.lock();
try {
if (!list.contains(item)) {
list.add(item);
}
} finally {
lock.unlock();
}
}
</string>
不推荐的做法:继承 ArrayList 并加 synchronized 方法
有人尝试通过继承并重写方法加 synchronized,但这无法覆盖所有潜在并发点(如迭代器、批量操作等),且破坏封装性,极易遗漏同步,导致隐性线程安全问题。JDK 明确不建议这种方式。
实际选型看读写比例和一致性要求:一般场景优先用 Collections.synchronizedList;读远大于写时用 CopyOnWriteArrayList;需要精准控制或混合操作时,手动加锁更可靠。不复杂但容易忽略细节。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










