🍔情景引入
我们看下面这段代码
运行后报错了
我们看看报错原因
报错原因是并发修改异常
🌺报错了,解决方法
⭐方法一
我们使用其他工具类,使用Collections,把HashSet转为synchronizedSet()
我们使用 Collections.synchronizedSet() 方法将普通的 HashSet 转换为一个线程安全的 Set 集合。通过对 set 进行同步化操作,可以保证在多线程环境下对 set 的访问是线程安全的。
Collections.synchronizedSet() 方法返回一个线程安全的 Set 对象,该对象内部使用同步机制来确保多线程环境下的安全访问。具体来说,它会对 Set 的各种操作(如添加、删除、迭代等)进行同步化处理,以避免并发修改引发的线程安全问题,比如数据不一致或异常。
好处如下:
- 线程安全:通过使用 Collections.synchronizedSet() 方法,
可以确保多个线程同时访问 set 时不会出现数据竞争和不一致的问题。这样可以提高程序的健壮性和可靠性
- 方便转换:通过使用 Collections.synchronizedSet() 方法,可以方便地将普通的集合类转换为线程安全的集合类,无需手动编写同步代码。
需要注意的是,虽然 Collections.synchronizedSet() 方法可以确保对集合的基本操作是线程安全的,但在进行复合操作时仍然需要额外的同步措施。例如,在循环遍历 set 并进行复合操作时,仍需要使用外部的同步机制,比如使用 synchronized 关键字或 Lock 接口。
此外,如果只是在单线程环境下使用集合,或者可以保证对集合的访问是单线程的,那么不一定需要使用线程安全的集合类。因为线程安全的集合类在性能上会有一些额外开销,所以在单线程环境下使用普通的集合类可能更加高效。
package org.Test6;
import java.util.*;
public class ListTest {
public static void main(String[] args) {
Set<String>set = Collections.synchronizedSet(new HashSet<>());
for (int i=0;i<10;i++){
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
⭐方法二
使用juc包下的CopyOnWriteArraySet方法
使用 CopyOnWriteArraySet 来创建一个线程安全的集合。CopyOnWriteArraySet 是 Java 并发包中提供的一种并发集合类,它具有以下好处:
- 线程安全:CopyOnWriteArraySet 是线程安全的集合类,可以在多线程环境中安全地进行读取和写入操作,而无需额外的同步措施。
- 写入时复制:CopyOnWriteArraySet 内部使用写入时复制的机制来保证线程安全。当对集合进行修改(添加、删除元素)时,
它会先将集合进行复制,然后在新副本上进行修改操作,最后再用新副本替换旧副本
。这样可以确保在进行修改操作时不会影响到正在进行迭代的线程,从而避免了传统集合类在迭代过程中需要额外的同步操作。
总之,CopyOnWriteArraySet 提供了一种简单而高效的线程安全集合解决方案,适用于特定的读多写少的并发场景。
package org.Test6;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
public class ListTest {
public static void main(String[] args) {
Set<String>set = new CopyOnWriteArraySet<>();
for (int i=0;i<10;i++){
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
在技术的道路上,我们不断探索、不断前行,不断面对挑战、不断突破自我。科技的发展改变着世界,而我们作为技术人员,也在这个过程中书写着自己的篇章。让我们携手并进,共同努力,开创美好的未来!愿我们在科技的征途上不断奋进,创造出更加美好、更加智能的明天!