_collections.synchronizedcollection_仅保证单个方法调用线程安全,不保障复合操作、遍历或组合动作的原子性;需手动同步多步逻辑和迭代,推荐优先使用concurrenthashmap等原生并发集合。

_Collections.synchronizedCollection_ 能让普通集合“变线程安全”,但这个“安全”是有明确边界的:它只保单个方法调用不乱,不保逻辑、不保遍历、不保组合动作。用错地方,照样出并发 bug。
单个操作确实安全
它把传入的集合(比如 ArrayList、HashSet)包装成代理对象,所有 public 方法(add、remove、contains、size 等)内部都加了 synchronized(mutex),锁对象默认是底层集合本身。这意味着:
- 两个线程同时调用
syncColl.add("x"),不会丢数据或破坏结构 -
syncColl.size()和syncColl.isEmpty()返回的是某一时刻的一致快照 - 只要不绕过包装器,直接操作原始集合,同步契约就成立
复合操作必须自己加锁
像“检查后添加”“先查再删”“批量处理+清空”这类多步逻辑,它完全不管:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 写法错误:
if (!syncColl.contains("a")) syncColl.add("a");—— 中间可能被其他线程插入相同元素 - 正确做法:把整段逻辑包进
synchronized(syncColl)块里,锁对象必须和包装器内部一致(即底层集合) - 常见场景还包括:条件更新、统计后修改、遍历中删除等,都得当一个原子单元来同步
迭代必须显式同步
iterator()、toArray()、增强 for 循环(底层就是 iterator)这些方法本身不加锁:
- 并发修改时大概率抛
ConcurrentModificationException - 也可能读到写线程正在更新的中间状态(脏读),尤其在高写频次下
- 正确写法:
synchronized(syncColl) { for (Object o : syncColl) { ... } }
更推荐用原生并发集合
除非兼容老代码,否则优先选 java.util.concurrent 包里的实现:
-
CopyOnWriteArrayList:读不加锁,适合监听器列表、配置快照等读远多于写的场景 -
ConcurrentHashMap:分段锁或 CAS + synchronized 优化,读几乎无锁,写吞吐高 -
BlockingQueue(如LinkedBlockingQueue):专为生产者-消费者设计,自带阻塞与唤醒机制
它们不是简单套个锁,而是从数据结构和算法层面做了并发适配,安全性更稳,性能也更可靠。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










