文档章节

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

东皇巴顿
 东皇巴顿
发布于 2017/04/05 16:48
字数 589
阅读 51
收藏 1
点赞 0
评论 0

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

© 著作权归作者所有

共有 人打赏支持
东皇巴顿
粉丝 3
博文 67
码字总数 75265
作品 0
海淀
技术主管
在windows上实现java6和Java8共存解决办法

问题背景 公司项目中应用到的jdk环境为1.6,最近在家学习IntelliJ IDEA中sdk多环境配置时,想安装Jdk1.8,作为学习基础。那么问题来了,公司项目扩展不支持jdk1.8,为了既能满足公司项目开发环...

ruanjun
01/14
0
0
OFbiz该如何安装部署?

我用的是WIN8,问题1:是不是这个系统不能安装部署? 我下载了JDK1.8,现在Oracle官网只有JDK1.7和JDK1.8两个了,没有JDK1.6以及以下版本了。问题2:是不是这个JDK无法安装部署OFbiz? 我从s...

文光
2014/07/21
7K
5
怎么修改jar包的jdk编译版本或者说怎么重新编译jar包

现在这个jar包是1.7编译的 本地jdk1.6可以用 1.8用不了 我想用jdk1.8编译一下 怎么操作

码农3123123
2017/12/07
18
1
Tomcat Unsupported major.minor version 52.0错误

Unsupported major.minor version 52.0: 看到Unsupported你是不是会想到jdk高版本能兼容低版本,但是低版本不能兼容高版本,不错,猜对了,其实就是这个意思。这个错误意思是你项目用JDK1.8运...

潜心笃志
03/08
0
0
Resin3.0.21启动报空指针

在jdk1.6下是好的,装了jdk1.8就会报这个错误,如下图: 这个问题是resin版本造成的吗,是不是我升级下resin就能解决这个问题

ForTheFree
2015/07/01
120
1
既有服务器上安装flume的JDK版本问题。

目前生产上跑着的应用使用的是JDK1.6(无法升级,各种原因)。现在想使用flume收集日志。 我看flume 要求jdk1.7以上,如果我再在服务器上安装一个jdk1.8 然后flume自己的配置文件单独制定这个...

StopTWorld
01/01
36
3
JDK API资源链接

JDK1.8 API HTML格式(在线英文):http://docs.oracle.com/javase/8/docs/api/index.html CHM格式(离线英文):http://download.csdn.net/download/u010188178/8114417 JDK1.7 API HTML格式......

lbb199197
2016/09/04
0
0
CopyOnWriteArrayList

除了加锁外,其实还有一种方式可以防止并发修改异常,这就是将读写分离技术(不是数据库上的)。 先回顾一下一个常识: 1、JAVA中“=”操作只是将引用和某个对象关联,假如同时有一个线程将引...

double_zp
2012/09/24
0
0
CopyOnWriteArrayList 简介

除了加锁外,其实还有一种方式可以防止并发修改异常,这就是将读写分离技术(不是数据库上的)。 先回顾一下一个常识: 1、JAVA中“=”操作只是将引用和某个对象关联,假如同时有一个线程将引...

凡16
2014/03/24
0
0
struts2 重定向redirect在centos6.6系统中不正常

系统:centOS6.6 JDK版本:1.8.0_131 Tomcat版本:8.0.45 Struts版本:2.5.10 由于前不久做系统升级,从JDK1.6升级到JDK1.8,编译后,通过浏览器访问项目,其中有个action是配置的是redirec...

flamehazi
2017/08/01
16
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

MacOS和Linux内核的区别

导读 有些人可能认为MacOS和Linux内核有相似之处,因为它们可以处理类似的命令和类似的软件。甚至有人认为苹果的MacOS是基于linux的。事实上,这两个内核的历史和特性是非常不同的。今天,我...

问题终结者
13分钟前
1
0
SpringBoot | 第八章:统一异常、数据校验处理

前言 在web应用中,请求处理时,出现异常是非常常见的。所以当应用出现各类异常时,进行异常的捕获或者二次处理(比如sql异常正常是不能外抛)是非常必要的,比如在开发对外api服务时,约定了响...

oKong
21分钟前
0
0
mysql高级

一、存储引擎 InnoDB MyISAM 比较 二、数据类型 整型 浮点数 字符串 时间和日期 三、索引 索引分类 索引的优点 索引优化 B-Tree 和 B+Tree 原理 四、查询性能优化 五、切分 垂直切分 水平切分...

丁典
41分钟前
1
0
rsync通过同步服务、系统日志、screen工具

rsync通过后台服务同步 在远程主机中建立一个rsync服务器,在服务器上配置好rsync的各种应用,然后将本机作为rsync的一个客户端连接远程的rsync服务器。 首先在A机器上建立并且配置rsync的配...

黄昏残影
今天
5
0
Spring Cloud Gateway 接口文档聚合实现

在微服务架构下,通常每个微服务都会使用Swagger来管理我们的接口文档,当微服务越来越多,接口查找管理无形中要浪费我们不少时间,毕竟懒是程序员的美德。 由于swagger2暂时不支持webflux 走...

冷冷gg
今天
115
2
流利阅读笔记31-20180720待学习

克罗地亚:输了世界杯,却赢了全世界 雪梨 2018-07-20 1.今日导读 1998 年,年轻的克罗地亚国家队在法国世界杯给全世界留下了不可磨灭的印象,格子军团一举夺得了季军。4 年后,克罗地亚折戟...

aibinxiao
今天
5
0
OSChina 周五乱弹 —— 我们是食物链的最底层

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @温家成 :分享谢安琪的单曲《姿色份子》 《姿色份子》- 谢安琪 手机党少年们想听歌,请使劲儿戳(这里) @贪吃飒:最近p2p怎么了、半个月爆了...

小小编辑
今天
877
14
Android Studio 3.0 之后打包apk出现应用未安装问题

1、废话 出现这个问题的原因,并不是只有一个,而是有多个原因,不懂的估计会被搞得一头雾水,下面我列举的是我遇到的几种问题和网友遇到的几种问题,但不一定是全部,也有可能有些莫名其妙的...

她叫我小渝
今天
0
0
前端基础

1. get请求传参长度的误区 误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的。 实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是...

wenxingjun
今天
0
0
拦截SQLSERVER的SSL加密通道替换传输过程中的用户名密码实现运维审计(一)

工作准备 •一台SQLSERVER 2005/SQLSERVER 2008服务 •SQLSERVER jdbc驱动程序 •Java开发环境eclipse + jdk1.8 •java反编译工具JD-Core 反编译JDBC分析SQLSERVER客户端与服务器通信原理 SQ...

紅顏為君笑
今天
15
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部