关于Iterator的fail-fast比较完整的解释请参考jdk中在Vector,ArrayList等具体实现时的相关描述:这里有一个比较清楚的翻译:
* Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,
* 当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照
* fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
*
* 所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象,
*Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
*
这里举一些列子进行分析:
1).当正在使用Iterator时,如果再使用Collection的add,remove或者其他的Iterator操作,将会抛出异常,java代码如下:
1: Collection c = new ArrayList();
2: Collection1.fill(c,1);
3: Collection1.print(c);
4: Iterator iterator_c = c.iterator();
5: Iterator iterator_c2 = c.iterator();
6: for(;iterator_c.hasNext();){
7: int i = (Integer)iterator_c.next();
8: System.out.println(i);
9: c.remove(i);
//iterator_c.remove();
10: if(iterator_c2.hasNext()){
iterator_c2.next();
iterator_c2.remove();
}
}
在第9行这里,使用iterator的同时又使用了Collection自带的c.remove()方法,抛出ConcurrentModificationException 异常;第十行使用了另外一个同属于c的Iterator,同样会抛出异常;
2):不同线程的迭代器操作(代码如下):
a.不同线程操作同一个collection的不同迭代器,或者一个操作迭代器,另一个操作collection;抛出异常,道理同上;
b.一个线程操作collection的迭代器,另外一个线程操作System.out.println(c);抛出异常,原因是在Collection.toString()中使用迭代器显示,本质道理同1);
c.AbstractList,abstractCollection中的addAll,removeAll方法都是用迭代器实现的;但是arrayList等容器重新实现了addAll(),也就是说 针对arraylist,linkedList如果你同时或者不同线程中使用了同一个对象的add和addAll方法.就不会出现异常;
但是,如果你本质上同时使用了add和removeAll(c),则会抛出异常.
总之,请确认你使用Iterator时本线程和其他线程中没有再操作该collection,如果不能避免这种情况,请换用其他的替代方案;
代码示例:
public class ThreadIterTest {
List a = new ArrayList();
List b = new ArrayList();
{
for(int i=0;i<1000000;i++){
a.add("a");
}
}
Thread t = new Thread(){
public void run(){
for(Iterator iter1= a.iterator();iter1.hasNext();){
System.out.println(iter1.next());
}
}
};
Thread t2 = new Thread(){
public void run(){
for(int i=0;i<1000;i++){
a.add(1);
}
}
};
Thread t3 = new Thread(){
public void run(){
a.removeAll(b);
}
};
public static void main(String[] args)throws Exception{
ThreadIterTest thread_iter = new ThreadIterTest();
//thread_iter.t.start();
thread_iter.t2.start();
thread_iter.t3.start();
// while(true){
// //toString(),removeAll中用到了Iter
// System.out.println(thread_iter.a);
// if(thread_iter.a.size()!=0){
// // b.addAll(thread_iter.a);
// //Thread.sleep(300);
//
// // b.removeAll(thread_iter.a);
//// System.out.println(b);
// }
// if(thread_iter.a.size()>50) break;
//
// }
}
}
t,t2,t3线程都有相互冲突的可能;