一、不安全集合类
说到不安全的集合类,一般会想到ArrayList,HashSet,HashMap,这三种最常用的。
二、ArrayList类的不安全性
不安全原因
ArrayList的底层是数组,new ArrayList()是定义一个空数组{},当添加数据的时候进行扩容,初次扩容容量默认为10,通过Arrays.copyOf(elementData, newCapacity)进行数组复制,实现扩容。为了满足高并发需求,并没有对ArrayList内的方法进行同步实现,这样就会出现多个线程同时进行数组复制操作,然后数据复制异常(ConcurrentModificationException)
解决方案
- 使用ArrayList的安全类Vector,Vector中的方法都是被synchronized关键字修饰的,每次调用添加方法只允许一个线程进行操作,保证了线程安全,降低并发量
- 使用Collectoins工具类的同步包装方法
List<String> list = Collections.synchronizedList(new ArrayList<>());
- 使用java.util.concurrent包下的CopyOnWriteArrayList类
- 代码:
List<String> list = new CopyOnWriteArrayList<>();
// 添加方法的源码
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
- 原理:在进行add方法时添加了ReentrantLock非公平锁,这样就可以保证只能由一个线程进行写操作
二、HashSet类的不安全性
不安全原因
HashSet的底层是HashMap,new HashSet()是new HashMap(),当添加数据的时候,添加的数据作为map的key,value为固定值PRESENT = new Object()。高并发情况下,进行抢占式写入操作时也会造成并发更新数据异常(ConcurrentModificationException)
解决方案
- 使用Collectoins工具类的同步包装方法
Set<String> set = Collections.synchronizedSet(new HashSet<>());
- 使用java.util.concurrent包下的CopyOnWriteArraySet类
- 代码:
Set<String> set = new CopyOnWriteArraySet<>();
// 底层调用还是CopyOnWriteArraySet
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
三、HashMap类的不安全性
不安全原因
HashMap的底层是数组+链表结构。高并发情况下,进行抢占式写入操作时也会造成并发更新数据异常(ConcurrentModificationException)
解决方案
- 使用Collectoins工具类的同步包装方法
Map<String, Object> map = Collections.synchronizedMap(new HashMap<>());
- 使用java.util.concurrent包下的ConcurrentHashMap类,它实现了ConcurrentMap接口
- 代码:
Map<String, Object> map = new ConcurrentHashMap<>();