arraylist非线程安全,应选用collections.synchronizedlist(轻量兼容)、copyonwritearraylist(读多写少)或手动加锁(复杂逻辑),禁用vector和继承加锁。

用 Collections.synchronizedList 包装
这是最轻量、兼容性最好的方式:把普通 ArrayList 包一层同步代理。
它在每个 public 方法(如 add、get、remove)内部加了 synchronized(this),保证单个操作原子性。
- 适合已有代码快速改造,无需改逻辑结构
- 注意:复合操作(比如“先检查再添加”或遍历)仍需手动加锁,否则不安全
- 遍历时必须显式同步整个 list 对象,否则迭代器会抛异常
示例:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
List
synchronized (safeList) {
for (String s : safeList) { ... }
}
用 CopyOnWriteArrayList 替代(读多写少首选)
这是 java.util.concurrent 提供的专用线程安全列表,核心是“写时复制”——每次 add/set/remove 都新建数组并复制全量数据,读操作全程无锁。
- 迭代绝对安全,不会抛 ConcurrentModificationException
- 读性能极高,适合监听器列表、配置缓存等场景
- 写操作开销大,频繁增删会显著影响吞吐和 GC 压力
- 迭代器看到的是快照,无法实时感知其他线程刚做的写入
示例:
List
cowList.add("item"); // 内部加 ReentrantLock,复制数组
String s = cowList.get(0); // 直接读原数组,无锁
手动加锁控制关键区段
当业务逻辑复杂(如“若不存在则添加”),或者需要更细粒度锁(避免锁整个 list),可用 ReentrantLock 或 synchronized 块包裹临界代码。
- 锁范围尽量小,只包真正共享状态的操作
- 避免嵌套锁或锁顺序不一致,防止死锁
- 适合与数据库事务、外部资源协同的复合操作
示例:
private final ReentrantLock lock = new ReentrantLock();
public void addIfAbsent(String item) {
lock.lock();
try {
if (!list.contains(item)) list.add(item);
} finally { lock.unlock(); }
}
不推荐的方式
Vector 虽然线程安全,但所有方法都 synchronized,锁粒度粗、性能差,且已属遗留类,JDK 文档明确建议优先使用 Collections.synchronizedList 或并发集合。
继承 ArrayList 并重写方法加 synchronized 是严重错误:无法覆盖底层非同步字段(如 elementData、size、modCount)的可见性与原子性,且破坏封装,极易出错。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










