Collections.synchronizedList() 返回线程安全列表,但仅保证单操作原子性;遍历时需手动同步底层对象,复合操作须加锁;适合读多写少场景,高并发可选CopyOnWriteArrayList等替代方案。

直接用 Collections.synchronizedList() 包装 ArrayList,能获得一个线程安全的列表视图,但要注意它只保证单个操作的原子性,复合操作仍需手动同步。
基本用法:创建同步包装列表
调用 Collections.synchronizedList() 并传入一个普通 ArrayList 实例,返回一个同步代理对象:
List<string> list = new ArrayList(); List<string> syncList = Collections.synchronizedList(list);</string></string>
此后对 syncList 的所有公开方法(如 add()、get()、remove())调用都会自动加锁,内部使用的是该列表对象自身的锁(this)。
遍历时必须手动同步
迭代器本身不是线程安全的。即使列表是同步的,直接用 for-each 或显式 iterator() 遍历仍可能抛出 ConcurrentModificationException,因为迭代过程涉及多个非原子操作。
正确做法是手动同步在原始列表对象上(即包装前的底层 ArrayList):
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 使用原始引用(推荐):
synchronized (list) { for (String s : list) { ... } } - 或用包装后的引用(等价):
synchronized (syncList) { ... },因为两者共享同一锁对象
复合操作需额外同步,不能依赖包装
像“检查是否存在再添加”这类逻辑(if (!list.contains(x)) list.add(x))不是原子的,两个线程可能同时通过检查,导致重复添加。
必须将整个复合操作包裹在同步块中:
synchronized (list) {
if (!list.contains("item")) {
list.add("item");
}
}
替代方案要考虑场景
Collections.synchronizedList() 适合读多写少、且复合操作可控的简单并发场景。若需更高并发性能或更丰富的线程安全行为,可考虑:
-
CopyOnWriteArrayList:适用于遍历远多于修改的场景,迭代器绝对安全,但写操作开销大 -
Vector:历史遗留类,所有方法同步,但设计较陈旧,一般不推荐新代码使用 - 显式使用
ReentrantLock或ConcurrentHashMap等更细粒度工具(当需要定制化控制时)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










