ArrayList本身非线程安全,需通过Collections.synchronizedList、手动加锁或CopyOnWriteArrayList实现线程安全;前者最简但迭代需额外同步,后者适合读多写少场景。

Java 中的 ArrayList 本身不是线程安全的,多线程环境下直接并发读写会引发 ConcurrentModificationException 或数据不一致问题。要实现线程安全的包装,核心思路是**控制对底层 ArrayList 的访问同步性**,常用方式有三种:使用 Collections.synchronizedList()、手动加锁、或改用更合适的并发集合(如 CopyOnWriteArrayList)。
用 Collections.synchronizedList 包装
这是最简单直接的包装方式,返回一个线程安全的 List 代理对象:
List<String> safeList = Collections.synchronizedList(new ArrayList<>());
它会在每个公共方法(如 add()、get()、size())内部加 synchronized 锁(锁的是 list 对象本身)。但要注意:
- 迭代操作仍需手动同步,否则可能抛出
ConcurrentModificationException - 复合操作(如“检查再插入”)不保证原子性,需额外同步
正确迭代示例:
立即学习“Java免费学习笔记(深入)”;
synchronized (safeList) {
for (String s : safeList) {
// 安全遍历
}
}
手动加锁控制访问
适合需要自定义同步粒度或组合操作原子性的场景。可使用 synchronized 块或 ReentrantLock:
private final List<String> list = new ArrayList<>();
private final Object lock = new Object();
public void addSafe(String item) {
synchronized (lock) {
list.add(item);
}
}
public String getSafe(int index) {
synchronized (lock) {
return list.get(index);
}
}
优点是锁对象可控、可细化(比如读写分离),缺点是代码量增加,易遗漏同步。
考虑 CopyOnWriteArrayList 替代方案
如果读多写少(如监听器列表、配置快照),CopyOnWriteArrayList 是更优选择:
- 所有可变操作(
add、set、remove)都复制底层数组,线程安全且迭代不抛异常 - 迭代器基于创建时的快照,不受后续修改影响
- 写操作开销大,不适合高频更新场景
使用方式简洁:
List<String> cowList = new CopyOnWriteArrayList<>();
不推荐的做法
直接继承 ArrayList 并重写方法加锁——破坏封装、难以覆盖所有路径(如父类调用、迭代器),且无法保证子类或反射绕过。应优先用组合 + 同步包装。
线程安全不是“加个 synchronized 就万事大吉”,关键看使用模式:纯读?读多写少?需要复合原子操作?选对工具比硬套锁更重要。


















