Set不安全
HashSet
底层使用的是什么?
我们去查看源码,点击进去一看发现

其实底层就是使用了HashMap
去实现的。
为什么Set不安全?
先给出代码
arduino
public class TestSet {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
for (int i = 0; i < 20; i++) {
int finalI = i;
new Thread(() -> {
set.add(String.valueOf(finalI));
System.out.println( set);
}, String.valueOf(i)).start();
}
}
}

发现在多线程下会出现ConcurrentModificationException
问题。
原因:
HashSet
是基于 HashMap
实现的,它本身并没有提供内置的线程安全机制。当多个线程同时对 HashSet
进行修改时(如执行 add()
操作),可能会导致 数据丢失 、数据不一致 ,甚至出现 ConcurrentModificationException
异常。
解决方案
1.显示加锁
ini
Set<String> set = new HashSet<>();
Object lock = new Object();
for (int i = 0; i < 20; i++) {
int finalI = i;
new Thread(() -> {
synchronized (lock) {
set.add(String.valueOf(finalI));
System.out.println(set);
}
}, String.valueOf(i)).start();
}
2. 使用 Collections.synchronizedSet()
vbnet
Set<String> set = Collections.synchronizedSet(new HashSet<>());
这样,所有对 set
的操作都将通过同步进行,从而避免了线程安全问题。然而,使用这种方式时需要注意,如果你要迭代 set
,仍然需要手动加锁,因为 synchronizedSet
仅保证基本的操作是同步的。
arduino
synchronized(set) {
for (String item : set) {
// 迭代操作
}
}
3. 使用 CopyOnWriteArraySet
CopyOnWriteArraySet
是一个线程安全的 Set
实现,底层使用 CopyOnWriteArrayList
。它适用于 读多写少 的场景,因为每次写操作都需要复制底层数据结构。但它在写操作频繁的场景下性能较差。
vbnet
Set<String> set = new CopyOnWriteArraySet<>();
CopyOnWriteArraySet
原理和CopyOnWriteArrayList
类似;