一、HasheSet 集合的不安全
1、故障现象
public class NotSafeSetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
//向集合添加内容
set.add(UUID.randomUUID().toString().substring(0, 8));
//从集合获取内容
System.out.println(set);
}, String.valueOf(i)).start();
}
}
}
运行结果:
2、分析
(1)HashSet 是线程不安全的
(2)HashSet 的底层是一个 HashMap(),但是这个 HashMap 的 value 永远是一个 Object 类型的常量(PRESENT),但HashSet的add是放一个值(调用map的PUT方法),而HashMap是放K、V键值对
public HashSet() {
map = new HashMap<>();
}
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
因为底层使用的是 HashMap,而 HashMap 也是线程不安全的,并且 HashSet 的 add 方法也没有使用 synchronized 同步锁。
二、方案一
1、使用 Collections 工具类
Collections 工具类也提供了线程安全的 Set 集合。
2、代码实现
public class SafeSetDemo {
public static void main(String[] args) {
Set<String> set = Collections.synchronizedSet(new HashSet<>());
for (int i = 0; i < 30; i++) {
new Thread(() -> {
//向集合添加内容
set.add(UUID.randomUUID().toString().substring(0, 8));
//从集合获取内容
System.out.println(set);
}, String.valueOf(i)).start();
}
}
}
三、方案二
1、使用 CopyOnWriteArraySet
原理同 CopyOnWriteArrayList。
2、代码实现
public class SafeSetDemo {
public static void main(String[] args) {
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
//向集合添加内容
set.add(UUID.randomUUID().toString().substring(0, 8));
//从集合获取内容
System.out.println(set);
}, String.valueOf(i)).start();
}
}
}
分类:
JUC
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器