collections.synchronizedlist仅保证单操作原子性,需手动同步复合操作、遍历及避免暴露原始列表,适用于读多写少场景;类型安全需显式声明泛型,否则运行时可能classcastexception。

直接用 Collections.synchronizedList 包装普通 ArrayList 能快速获得线程安全的 List 视图,但它不是“开箱即用”的万能方案——关键在于理解它只保单操作原子性,其余都得你来兜底。
初始化必须封死访问路径
变量声明要 final,原始列表不能暴露,否则同步形同虚设:
- ✅ 正确写法:
private final List<string> safeList = Collections.synchronizedList(new ArrayList());</string> - ❌ 错误写法:
List<string> raw = new ArrayList(); List<string> safe = Collections.synchronizedList(raw);</string></string>—— 后续若有人直接操作raw,锁完全失效 - 避免调用
subList()、Arrays.asList(safeList)等生成非同步视图,它们不继承同步能力
遍历和复合操作必须手动加锁
synchronizedList 返回的迭代器本身不带同步,for-each 或 iterator 遍历时仍会抛 ConcurrentModificationException:
- 正确做法:用
synchronized(safeList) { ... }包裹整个遍历块,锁对象必须是包装后的列表(或其底层原始引用,二者等价) - “检查再添加”这类逻辑(如
if (!safeList.contains(x)) safeList.add(x))不是原子的,必须放在同一同步块内执行 - 不要用
new Object()或其他无关对象做锁——锁对象不一致等于没锁
选它还是换别的?看场景再决定
它适合读远多于写、且你能控制访问方式的轻量并发场景:
- ✔️ 推荐用
Collections.synchronizedList:写操作极少(如配置监听器注册)、元素较大(复制成本高)、需强实时一致性(CopyOnWriteArrayList 迭代看到的是快照) - ✔️ 推荐换
CopyOnWriteArrayList:遍历极其频繁、写操作极少、能接受写时复制开销和内存压力 - ⚠️ 不适合:写操作密集(如每秒几十次以上)、要求高吞吐或低延迟——此时考虑
ConcurrentLinkedQueue或分段锁结构
泛型与类型安全别掉链子
Collections.synchronizedList 是静态工厂方法,返回的是擦除泛型后的 List 接口,运行时无法校验类型:
- 混用原始类型(
List)和参数化类型(List<string></string>)可能引发ClassCastException,编译期却不会报错 - 始终显式声明泛型,例如
Collections.synchronizedList(new ArrayList<string>())</string>,避免类型擦除带来的隐患 - 不要把同步列表传给不守约定的工具方法——若对方内部绕过同步调用,安全性就崩了
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











