在JDK1.6中对于一个集合进行迭代(hasNext)的过程中,对这个集合进行动态的add或remove,程序会抛出ConcurrentModificationException的异常;但是,在迭代的过程中对这个集合进行sort排序,程序不会发生异常。
在JDK1.8中,除了迭代过程中add或remove这个集合会ConcurrentModificationException;如果迭代过程中对这个集合进行sort排序,也会ConcurrentModificationException。
这个行为可能引发:在JDK1.6上执行不报错的代码,在JDK1.8上出现ConcurrentModificationException的报错。
示例代码:
package com.lands.concurrent;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Vector;
public class ConcurrentModificationExceptionTest {
public static void main(String[] args) {
//when iterator, add or remove orignal colleciton.
//1.6.0_31 throws ConcurrentModificationException.
//1.8.0_92 throws ConcurrentModificationException.
//test1();
//when iterator, sort orignal colleciton.
//1.6.0_31 correct.
//1.8.0_92 Both collections.sort and List.sort throws ConcurrentModificationException.
test2();
}
private static void test1() {
Vector list = new Vector();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
Iterator itor = list.iterator();
while (itor.hasNext()) {
String temp = (String) itor.next();
System.out.println(temp);
if (temp.equals("c"))
list.add("g");
//list.remove("e");
}
}
private static void test2() {
Vector list = new Vector();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
Iterator itor = list.iterator();
while (itor.hasNext()) {
String temp = (String) itor.next();
System.out.println(temp);
if (temp.equals("c"))
Collections.sort(list);
// list.sort(new Comparator(){
// @Override
// public int compare(Object o1, Object o2) {
// return 0;
// }
// });
}
}
}
从Oracle官方,已经可以看到这个问题的报告,但官方的态度是“Not an issue”(不是问题,不修复)。根据API文档对于Iterator的行为是这样定义的“... The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way ... ”,翻译过来就是“...在迭代的过程中对底层集合进行任何形式的编辑,将导致集合迭代行为的不确定性...”。所以,如果以前在JDK1.8之前,可能运行正常的“迭代过程中排序”的代码,是一种并不规范的写法。
Oracle Bugs的几个报告链接:
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6687277
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8157645
JDK1.6 vs JDK1.8的sort代码的变化:
JDK1.6 - Collections.sort(list)逻辑。
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
JDK1.8 - Collections.sort(list)逻辑。
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
@SuppressWarnings("unchecked")
@Override
public synchronized void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, elementCount, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++; --此句是重点,sort会改变modCount。当本次迭代通过之后,下一个迭代进来时,必然导致“modCount != expectedModCount”,抛出ConcurrentModificationException。
}