Collections.synchronizedList仅保证单个方法调用的线程安全,复合操作、锁对象误用及高并发场景下需手动同步或改用更合适的并发集合。

Collections.synchronizedList 不是“开箱即用”的线程安全银弹,它只在明确边界内有效:单个方法调用安全,其余都得靠你手动兜底。
它能守住的底线:单操作原子性
对包装后的列表调用 add()、get(int)、remove(Object)、size()、contains() 等公开方法时,内部已加 synchronized 锁(锁对象是底层原始 List 实例),多个线程并发调用这些方法不会导致数据结构损坏或抛出 ArrayIndexOutOfBoundsException。
- add("x") → 安全
- get(0) → 安全
- remove("y") → 安全
- 但 list.get(i) 和 list.remove(i) 连续调用 → i 可能已失效,不安全
它守不住的关键场景:复合操作必须显式同步
任何依赖中间状态、跨多个方法调用的逻辑,都不受保护。典型如“检查后执行”“遍历中修改”“读-改-写”,必须用 synchronized 块包裹原始列表或包装后列表(二者锁对象相同)。
- if (!list.contains("a")) list.add("a"); → 必须整个块 synchronized(list)
- for (String s : list) { if (s.isEmpty()) list.remove(s); } → 必须外层 synchronized(list)
- Iterator it = list.iterator(); while(it.hasNext()) {...} → 同样必须包在 synchronized(list) 内
它容易被绕过的隐患:锁对象暴露与误用
安全性完全依赖“所有访问都走同一把锁”。一旦破坏这个前提,同步即失效。
立即学习“Java免费学习笔记(深入)”;
- 把原始 ArrayList(未包装前)传给其他模块并被直接使用 → 同步彻底失效
- 用 synchronized(new Object()) 替代 synchronized(list) → 锁对象不一致,形同虚设
- 将 synchronizedList 存入 ConcurrentHashMap 后,仅对 map 操作加锁,却忽略 list 自身操作 → 锁粒度错配
- 通过 new ArrayList(synchronizedList) 构造新列表 → 绕过所有同步机制
它该退场的时刻:性能或语义不匹配
当出现以下情况,说明 Collections.synchronizedList 已超出适用边界,应转向更合适的方案:
- 写操作频繁且含随机位置更新(如大量 set(i, x) 或 remove(i))→ CopyOnWriteArrayList 复制开销过大,考虑分段锁或 ConcurrentLinkedQueue + 索引映射
- 读写并发极高,单锁成为瓶颈 → 改用 java.util.concurrent 中的并发集合,如 CopyOnWriteArrayList(遍历极多、写极少)、ConcurrentSkipListList(需排序+高并发)
- 需要迭代时看到最新写入(而非快照)且不能容忍 size() 在循环中突变 → synchronizedList 更合适,但必须全程严格同步
- 元素体积大(如含大 byte[] 的对象)→ 复制成本高,synchronizedList 的内存友好性成为优势


















