Java 而Collections.shuffle()不';t抛出ConcurrentModificationException

Java 而Collections.shuffle()不';t抛出ConcurrentModificationException,java,collections,Java,Collections,实际上,我正在学习集合和异常,我不明白为什么会这样: List<Integer> intList = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,10)); for (Integer s : intList) { Collections.shuffle(intList); System.out.println(s); } List intList=newarraylist(Array

实际上,我正在学习集合和异常,我不明白为什么会这样:

List<Integer> intList = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
for (Integer s : intList) {
     Collections.shuffle(intList);
     System.out.println(s);
 }
List intList=newarraylist(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
对于(整数s:intList){
集合。洗牌(intList);
系统输出打印项次;
}
在阅读文档时,它指出

此异常可能由检测到并发的方法引发 当不允许修改对象时,对对象进行修改

查看集合的源代码:

public static void shuffle(List<?> list) {
        if (r == null) {
            r = new Random();
        }
        shuffle(list, r);
}
publicstaticvoidshuffle(列表){
if(r==null){
r=新随机数();
}
洗牌(列表,r);
}
我来看看洗牌功能:

public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=size; i>1; i--)
                swap(list, i-1, rnd.nextInt(i));
        } else {
            Object arr[] = list.toArray();

            // Shuffle array
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextInt(i));

            // Dump array back into list
            ListIterator it = list.listIterator();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);
            }
        }
    }
public static void swap(List<?> list, int i, int j) {
        final List l = list;
        l.set(i, l.set(j, l.get(i)));
}
publicstaticvoidshuffle(列表,随机rnd){
int size=list.size();
if(大小1;i--)
掉期(清单,i-1,rnd.nextInt(i));
}否则{
对象arr[]=list.toArray();
//洗牌阵列
对于(int i=size;i>1;i--)
掉期(arr,i-1,rnd.nextInt(i));
//将数组转储回列表
ListIterator it=list.ListIterator();
对于(int i=0;i而言,答案在于-强调矿山:

(结构修改是添加或删除一个或多个元素,或显式调整支持数组大小的任何操作;仅设置元素的值不是结构修改。

此类迭代器和listIterator方法返回的迭代器故障快速:如果在创建迭代器后的任何时间以任何方式修改列表,迭代器将抛出ConcurrentModificationException,除非通过迭代器自己的remove或add方法定义后,迭代器将快速、干净地失败,而不是在将来的不确定时间冒任意、不确定行为的风险

shuffle
只调用
set
,因此它不执行结构修改,因此迭代器不会抛出异常。

答案在于-强调:

 for (int i=size; i>1; i--)
   swap(list, i-1, rnd.nextInt(i));
(结构修改是添加或删除一个或多个元素,或显式调整支持数组大小的任何操作;仅设置元素的值不是结构修改。

此类迭代器和listIterator方法返回的迭代器故障快速:如果在创建迭代器后的任何时间以任何方式修改列表,迭代器将抛出ConcurrentModificationException,除非通过迭代器自己的remove或add方法定义后,迭代器将快速、干净地失败,而不是在将来的不确定时间冒任意、不确定行为的风险

shuffle
仅调用
set
,因此它不执行结构修改,因此迭代器不会引发异常

 for (int i=size; i>1; i--)
   swap(list, i-1, rnd.nextInt(i));
从本质上讲,这里没有迭代;没有涉及到
迭代器
。在第二个分支中,它通过
迭代器
进行所有修改,这就是您应该如何避免ConcurrentModificationException的


本质上,这里没有迭代;这里没有涉及到
迭代器
。在第二个分支中,它通过
迭代器
进行所有修改,这就是您应该如何做的,以避免ConcurrentModificationException。

我认为这里的修改意味着添加(或)删除会改变列表的大小,而不是交换。它可能是特定于实现的,但是
set
通常不会更改运行整个
ConcurrentModificationException
show的
modCount
。我认为这里的修改意味着添加(或)remove会改变列表的大小,而不是SWAP。它可能是特定于实现的,但是
set
通常不会更改运行整个
ConcurrentModificationException
modCount
shuffle
只调用
set
-在这个特定的实现中。@Holger:是的,没错。我认为不只是执行交换是一个不寻常的实现。“
shuffle
只调用
set
”-在这个特定的实现中。@Holger:是的,没错。我认为不只是执行交换是一个不寻常的实现。