ConcurrentModificationException - JDK1.6 与JDK1.8的差异

在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。
    }    

转载于:https://my.oschina.net/blacklands/blog/873528

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值