Collections.synchronizedList仅保证单个方法原子性,遍历时仍抛ConcurrentModificationException,因其迭代器未加锁且无fail-safe机制;复合操作须手动synchronized(list)块保护。

Collections.synchronizedList 返回的不是“开箱即用”的线程安全集合,它只保证单个操作原子,复合操作仍需手动同步。
为什么遍历时抛 ConcurrentModificationException
即使用了 Collections.synchronizedList,在迭代过程中其他线程修改列表(如 add 或 remove),依然会触发 ConcurrentModificationException。这是因为它的迭代器不加锁,且未做 fail-safe 处理。
- 必须在
for循环或iterator()外显式加synchronized块,锁对象是该 list 的包装实例(不是原始 list) - 错误写法:
for (String s : syncList) { ... }—— 隐式调用iterator(),无同步保护 - 正确写法:
synchronized (syncList) { for (String s : syncList) { // 安全 } }
addAll、removeAll 等批量方法是否线程安全
是的,addAll、removeAll、retainAll 这些方法内部已用 synchronized 包裹,无需额外同步。但要注意:它们只保证自身执行期间不被其他线程打断,不保证调用前后状态一致(比如 A 线程刚 addAll 完,B 线程立刻 clear,结果仍是竞态)。
- 这些方法底层调用的是被包装 list 的对应方法,并套了一层
synchronized (mutex) -
mutex默认是this(即 synchronizedList 实例本身),也可通过构造函数传入自定义锁对象 - 性能上,每次调用都进锁,高并发下吞吐量不如
CopyOnWriteArrayList
和 CopyOnWriteArrayList 的关键区别在哪
根本差异在于读写策略:Collections.synchronizedList 是读写都阻塞,CopyOnWriteArrayList 是写时复制、读不加锁。
- 适合读多写少场景?选
CopyOnWriteArrayList;写频繁或内存敏感?慎用,因为每次写都复制整个数组 -
synchronizedList支持null元素,CopyOnWriteArrayList也支持(JDK 8+) -
synchronizedList迭代器弱一致性(可能看到部分更新),CopyOnWriteArrayList迭代器强一致性(快照) - 不能混用:把
CopyOnWriteArrayList传给Collections.synchronizedList没意义,后者只是再套一层无实际增益的锁
真正容易被忽略的是:几乎所有“安全”错觉都来自对“单个方法线程安全”的过度解读。只要逻辑涉及多个方法调用(比如先 size() 再 get(0)),就必须自己加锁——这个锁对象,得是那个 synchronizedList 实例本身。

















