Collections.synchronizedList返回线程安全的List包装器,其单个方法调用原子但迭代需手动同步,适合读多写少场景。

Java 中 ArrayList 本身不是线程安全的,多个线程同时读写时可能抛出 ConcurrentModificationException,或出现数据丢失、脏读等不可预期行为。用 Collections.synchronizedList 是一种简单有效的同步包装方案,但要注意它只提供“方法级同步”,不是万能锁。
什么是 Collections.synchronizedList?
它返回一个线程安全的 List 包装器,底层仍使用原始 ArrayList,所有 public 方法(如 add、get、remove)都加了 synchronized 锁(锁在 list 对象自身上)。这意味着单个操作是原子的,但多个操作组合仍需手动同步。
基本用法:包装 ArrayList
只需一行代码即可获得线程安全的列表:
List<String> safeList = Collections.synchronizedList(new ArrayList<>());
之后可像普通 List 一样调用 add()、get()、size() 等方法,每个调用都是线程安全的。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
关键注意事项:迭代必须手动同步
这是最容易出错的地方:synchronizedList 的 iterator() 或 forEach() 不受自动保护。若在遍历时其他线程修改列表,仍会触发 ConcurrentModificationException。
正确做法是显式对 list 对象加锁:
- 使用
synchronized (safeList) { ... }包裹整个迭代逻辑 - 避免在循环中调用
safeList.remove()等结构性修改方法(除非也在同步块内) - 示例:
synchronized (safeList) {
for (String s : safeList) {
System.out.println(s);
}
}
替代方案对比:什么时候该选别的?
Collections.synchronizedList 适合读多写少、操作简单、并发压力不大的场景。若需更高性能或更复杂并发控制,可考虑:
-
CopyOnWriteArrayList:写操作复制数组,读完全无锁,适合读极多、写极少的场景(如监听器列表) -
Vector:历史遗留类,方法全加 synchronized,但性能差、API 过时,不推荐新代码使用 - 显式
ReentrantLock+ 普通ArrayList:灵活性高,但需自行管理锁粒度和异常释放

















