前言
在提到多线程的时候我们大都会想到ArrayList 与 HashMap,这两个类型都是非线性安全的!在多个线程同时操作改集合对象时,会出现哪些问题呢?在传统的集合包内的集合类到底为什么线程非安全呢?在新的JUC包类又有什么可以替代呢?
介绍
①为什么ArrayList 是线性不安全的?
②替代措施及解决方案?
ArrayList 我们都知道底层是以数组方式实现的,实现了可变大小的数组,它允许所有元素,包括null。看下面一个例子:开启多个线程操作List集合,向ArrayList中增加元素,同时去除元素。
importjava.util.ArrayList;importjava.util.Collections;importjava.util.List;importjava.util.Vector;public classListTest {//ArrayList
protected static ArrayList arrayList = new ArrayList();//解决措施①:使用Vector集合
protected static Vector arrayListSafe1 = new Vector();//解决措施②:我们加上Collections.synchronizedList,它会自动将我们的list方法进行改变,最后返回给我们一个加锁了List
static List arrayListSafe2 = Collections.synchronizedList(new ArrayList());public static voidmain(String[] args) {
Thread[] threads= new Thread[500];for (int i = 0; i < threads.length; i++) {
threads[i]= newArrayListThread();
threads[i].start();
}for (int i = 0; i < threads.length; i++) {try{
threads[i].join();//等待该线程终止
} catch(InterruptedException e) {
e.printStackTrace();
}
}//输出list中的对象元素
for (int i = 0; i < threads.length; i++) {
System.out.println(arrayList.get(i));
}
}
}/*** 线程类,执行arrayList的add()增加方法
*
*@authorzyx
**/
class ArrayListThread extendsThread {
@Overridepublic voidrun() {try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}//增加元素
ListTest.arrayList.add(Thread.currentThread().getName());
}
}
View Code
运行代码结果可知,会出现以下几种情况:
①Null
②某些线程并未打印
③数组下标越界异常
由此我们可以得出,在多线程情况下操作ArrayList 并不是线性安全的。那如何解决呢?
第一种方案:
使用Vertor集合
protected static Vector arrayListSafe1 = new Vector();
View Code
第二种方案:
使用Collections.synchronizedList。它会自动将我们的list方法进行改变,最后返回给我们一个加锁了List
protected static List arrayListSafe2 = Collections.synchronizedList(new ArrayList());
View Code
第三种方案:
使用JUC中的CopyOnWriteArrayList类进行替换。具体详情可参考JUC框架
常见集合线性是否安全可参考下图:
参考文章: