最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Java集合并发安全:Collections.synchronizedSet实战应用
时间:2026-06-25 08:21:46 编辑:袖梨 来源:一聚教程网
Collections.synchronizedSet()仅保证单个方法原子性,复合操作和迭代需手动同步;正确做法是以该Set实例为锁对象加synchronized块,遍历时也需同步或转数组;高并发场景推荐ConcurrentHashMap.newKeySet()或ConcurrentSkipListSet。
直接用 Collections.synchronizedSet(new HashSet()) 能让单个 add、remove、contains 操作线程安全,但复合逻辑和迭代仍会出错——关键不在“包没包好”,而在“怎么用才不出问题”。
单方法安全,不代表整体安全
包装后的 Set 确保每个 public 方法(如 add()、contains())是原子的,但多个方法组合就不受保护。比如下面这段代码在多线程下可能重复添加:
-
if (!set.contains("x")) set.add("x");—— 判断和添加之间存在时间窗口,两个线程都通过判断后执行 add - 类似地,
removeIf、retainAll等批量操作也不具备原子性
复合操作必须加同步块
正确做法是用该同步 Set 实例本身作锁对象,不要另建新锁:
- ✅ 正确:
synchronized (syncSet) { if (!syncSet.contains("key")) syncSet.add("key"); } - ❌ 错误:
synchronized (new Object()) { ... }或synchronized (this) { ... }—— 锁对象不一致,不同步 - 注意:
syncSet内部的mutex字段不可见,但其自身就是锁对象,这是 Collections.synchronizedSet 的设计约定
遍历必须手动同步,否则抛异常
即使 Set 是同步的,它的迭代器不是线程安全的。并发修改+遍历大概率触发 ConcurrentModificationException:
立即学习“Java免费学习笔记(深入)”;
- ✅ 安全遍历:
synchronized (syncSet) { for (String s : syncSet) { ... } } - ✅ 替代方案(读多写少且数据量小):
for (String s : syncSet.toArray()) { ... } - ❌ 危险操作:边遍历边调用
remove()或add(),除非整个操作都在同一synchronized块内
高并发场景建议换 ConcurrentSet
Collections.synchronizedSet 是全局独占锁,吞吐量低。如果业务读多写少、或并发压力大,优先考虑:
-
ConcurrentHashMap.newKeySet()(Java 8+):底层基于分段锁/CAS,支持无锁读、并发写,性能显著更好 -
ConcurrentSkipListSet:有序、并发安全,适合需要排序的场景 - 注意:
newKeySet()迭代器不保证强一致性(可能漏元素或看到旧值),但绝大多数业务可接受
相关文章
- 无限暖暖2.1版本下半奇迹之冠巅峰赛通关指南 06-27
- 逆战未来收藏室解锁攻略 06-27
- 逆战未来武器强度榜分析一览 06-27
- 心动小镇园艺怎么快速升级 06-27
- 息风谷战略邪线结局攻略 06-27
- 心动小镇水豚吃什么食物 06-27