一、问题
在开发中会经常使用ArrayList、Set、Map集合来存取数据,当我们在单线程下这种方式是没有任何问题的。但是当遇到多个线程来进行操作的时候就会出现问题。
下面是示例:
//用30个线程来进行操作,给list中添加一个8位的随机数
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
for(int i=0;i<30;i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
}
},String.valueOf(i)).start();
}
}
就会报java.util.ConcurrentModificationException,就是并发修改异常
二、解决方式:
1、使用Vector集合,但是他的每个方法都加上了synchronized同步,所以并发性能降低。
2、使用Conllections工具类:
public static void main(String[] args) {
//List<String> list=new ArrayList<String>();
List<String> list=Collections.synchronizedList(new ArrayList<>());
for(int i=0;i<30;i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
}
},String.valueOf(i)).start();
}
}
运行结果完全没毛病;
3、使用CopyOnWrite类,既写时复制容器
就将上面的List<String> list=Collections.synchronizedList(new ArrayList<>());
改为List<String> list=new CopyOnWriteArrayList<>()
就行;
介绍下CopyOnWrite----写时复制容器:
当我们往一个容器中添加元素时,不直接在当前容器Object[] 添加。而是将这个容器进行Copy,复制出一个新的容器 object[] newElements,然后向新容器中添加元素,添加完元素之后,再将原容器的引用指向新容器。这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite也是读写分离的思想。