有哪些集合是线程不安全的?如何解决?

【CSDN】集合类线程不安全如何解决

List|ArrayList

public static void main(String[] args) {

List<String> list = new ArrayList<>();
for (int i = 1; i <=20 ; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}

多线程环境下并发操作ArrayList操作发生异常

解决ArrayList线程不安全

  • 使用Vector
  • 使用Collections.synchronizeList()
  • 使用CopyOnWriteArrayList()

Vector

Vector底层采用的是加锁的方式,加锁数据的一致性可以保证,但并发性会大大降低。

Collections.synchronizeList()

Collection和Collections的区别:

  • Collection是一个接口,Set接口和List接口都继承自此接口
  • Collections是一个类,一个辅助工具类,可以使不安全的集合类变为安全的


CopyOnWriteArrayList()

如果是读多写少的情况,推荐使用CopyOnWriteArrayList;

CopyOnWriteArrayList是JUC包下的一个类。写时复制基于读写分离的思想。

CopyOnWrite的add方法,使用Lock来加锁,一次只允许一个线程进行写操作

CopyOnWrite容器被称为写时复制的容器,往一个容器当中添加元素的时候,不直接往当前容器Object[] 添加,而是先将当前的容器Object[] 进行copy,复制出一个新的容器Object[] newElements,往新容器里添加元素,元素添加完成之后,将原容器的引用指向新的容器。
这样做的好处是可以并发的读,而不需要加锁。

Set|HashSet

HashSet底层实现

HashMap以键值对储存数据,而HashSet中add方法只添加一个元素。
value值是一个Object类型的常量,HashSet不关心value值。

解决HashSet线程不安全

public static void main(String[] args) {
Set<String> set=new HashSet<>();
for(int i=1;i<=40;i++){
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}

Collections.synchronizeSet

CopyOnWriteHashSet

JUC包下的一个类

Map|HashMap

解决HashMap线程不安全

HashTable

Collections.synchronizedMap

ConcurrentHashMap

JUC下的包

拓展知识点-JUC

JUC系列(一)| 什么是JUC?