collections.synchronizedlist仅保障单个操作线程安全,遍历、复合操作等仍需手动同步;必须用final声明并避免暴露底层引用,且不可使用sublist等非同步视图。

Collections.synchronizedList 能快速给 ArrayList 加上基础线程安全,但它不是“开箱即用”的万能方案——单个 add、get 是安全的,但遍历、条件判断、复合逻辑仍需你亲手加锁。
初始化必须用 final 且不暴露原始引用
声明变量时加上 final,防止被意外替换或外部直接操作底层列表:
- ✅ 正确写法:private final List
list = Collections.synchronizedList(new ArrayList()); - ❌ 错误写法:List
raw = new ArrayList(); List —— 后续若有人直接用sync = Collections.synchronizedList(raw); raw.add(),同步完全失效 - 避免后续调用
subList()或Arrays.asList(syncList),这些返回的是非同步视图,锁不起作用
遍历时必须手动同步整个块
它的迭代器本身不带同步能力,裸用 for-each 或 iterator() 在多线程下大概率抛 ConcurrentModificationException:
- ✅ 安全遍历:synchronized (list) { for (String s : list) { /* 处理 */ } }
- ✅ 获取迭代器也得在同步块内:synchronized (list) { Iterator
it = list.iterator(); while (it.hasNext()) { ... } } - ⚠️ 注意:锁对象必须是
list(即 synchronizedList 返回的对象),它和底层 ArrayList 共享同一把锁
复合操作不能依赖包装,必须整体加锁
像“检查再添加”“先 size() 再 get(0)”这类两步逻辑,中间可能被其他线程插入或删减,导致逻辑错乱或异常:
- ❌ 危险写法:if (!list.contains("x")) list.add("x");
- ✅ 正确做法:synchronized (list) { if (!list.contains("x")) list.add("x"); }
- 类似场景还包括:
isEmpty() ? add(...) : ...、size() > 0 ? get(0) : null,都必须包裹在同步块中
适用场景与替代方案参考
它适合读多写极少、业务逻辑简单、且能接受串行化访问的轻量并发场景:
- ✅ 推荐用:读操作远多于写,且没有复杂遍历+修改混合逻辑
- ? 可考虑 CopyOnWriteArrayList:遍历极其频繁、写操作稀疏(如监听器列表),迭代器绝对安全,但写操作复制数组开销大
- ? 少用 Vector:所有方法都 synchronized,设计陈旧,性能更差,新代码不推荐
- ⚡ 高并发写多场景:考虑 ConcurrentHashMap + 自定义结构,或 ReentrantLock 配合普通 ArrayList 实现细粒度控制
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











