不安全的集合类
在并发环境下,我们经常使用的集合类(List、Map、Set)其实都是不安全的!
List
List在单线程的情况下是安全的,但是多线程的情况下是不安全的,我们来看两段代码:
单线程
public class UnsafeList1 {
public static void main(String[] args) {
List<String> list= Arrays.asList("a","b","c");
list.forEach(System.out::println);
}
}

多线程
public class UnsafeList2 {
public static void main(String[] args) {
ArrayList<Object> list=new ArrayList<>();
for (int i = 1; i <=30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}

通过以上两段代码,我们可以看到,在多线程情况下会报ConcurrentModificationException(并发修改)异常,那我们如何去保证在多线程的情况下List的安全了,有以下三中方法:
- 使用Vector,我们都知道Vector是线程安全的。
public class UnsafeList2 {
public static void main(String[] args) {
List<String> list=new Vector<>();
for (int i = 1; i <=30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}

2.利用Collections类下的方法synchronizedList,将其变为安全的集合类。
public class UnsafeList2 {
public static void main(String[] args) {
List<String> list= Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i <=30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}

3. 使用CopyOnWriteArrayList。
public class UnsafeList2 {
public static void main(String[] args) {
List<String> list=new CopyOnWriteArrayList<>();
for (int i = 1; i <=30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}

三种方式比较:
Vector
我们首先看下Vector和ArrayList的源码,


通过源码我们知道Vector在JDK1.0的时候就已经有了,而ArrayList是在JDK1.2才有的,不知道大家有没有想过这样一个问题,Vector既然已经处理了线程不安全的问题,为什么还有添加一个不安全的ArrayList呢?其实是有原因的,虽然实现了List接口,底层都是数组,但是Vector的性能却比ArrayList低。所以我们一般的话不采用Vector。
synchronizeList
通过源码分析,它是通过给自己本身暴力加锁而实现线程安全的,所以效率也比较低下,但是相对于Vector高点。
CopyOnWriteArrayList
CopyOnWriteArrayList其实利用了计算机领域的一个COW思想,多个调用者,想调用相同的资源,改变指针指向;在多线程下如果只是去读,就不会产生锁! 假如你是去写,就需要拷贝一份都自己哪里,修改完毕后,再替换指针!这样写的话保证数据的安全,效率也高,推荐使用!

Map
还是首先来一段代码:
public class UnsafeMap {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
for (int i = 1; i <= 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}

我们可以看到,HashMap是不安全的,解决方案就是使用HashTablehe和ConcurrentHashMap。HashTable效率低下,不建议使用!
Set
public class UnsafeSet1 {
public static void main(String[] args) {
Set<String> set =new HashSet<>();
for (int i = 1; i <=30 ; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}

Set的底层是HashMap,HashMap是不安全的,所以Set自然也是线程不安全的。解决方案就是synchronizedSet和CopyOnWriteSet。
本文深入探讨了在并发环境中,常用的集合类如List、Map和Set的线程安全性问题。详细介绍了List类在多线程下可能引发的ConcurrentModificationException异常,并提供了三种解决方案:使用Vector、利用Collections.synchronizedList方法和采用CopyOnWriteArrayList。同时,文章对比了这三种方案的性能和适用场景。此外,还讨论了Map和Set在并发环境下的不安全性及推荐的解决策略。
996

被折叠的 条评论
为什么被折叠?



