Java集合的快速失败机制 “fail-fast”?
答:
是java集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。
例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制。
原因:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值(无论是add()、remove(),还是clear(),只要涉及到修改集合中的元素个数时,都会改变modCount的值)。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
解决办法:
-
在遍历过程中,所有涉及到改变modCount值得地方全部加上synchronized。
-
使用CopyOnWriteArrayList来替换ArrayList
3.如果使用vector替换arraylist,仍会报currentModificationException
Vector源码可以发现它的很多方法都加上了synchronized来进行线程同步,例如add()、remove()、set()、get(),但是Vector内部的synchronized方法无法控制到遍历操作,所以即使是线程安全的Vector也无法做到线程安全地遍历。
如果想要线程安全地遍历Vector,需要我们去手动在遍历时给Vector加上synchronized锁,
并发容器支持并发的遍历和并发的更新。
主要的类有ConcurrentHashMap, CopyOnWriteArrayList 和CopyOnWriteArraySet
public class DelArrayList<E> {
public static List<Integer> list=new ArrayList<>();
public DelArrayList(){
for(int i=0;i<6;i++){
list.add(i);
}
}
/**
* @param args
* <p>
* Description:
* </p>
*/
private static class ThreadA extends Thread{
public void run(){
Iterator it=list.iterator();
while(it.hasNext()){
System.out.println(it.next());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static class ThreadB implements Runnable{
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.remove(2);
}
}
image.png
网友评论