这个就是实现一个简单的 ArrayList 的遍历,如果存在一个为“aaa”的值,就添加一个“ccc”

package Array;

import java.util.ArrayList;
import java.util.Iterator;public class demo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
demo2.bianli(list); } public static void bianli(ArrayList<String> list) {
Iterator<String> it = list.iterator(); // 1.迭代器:java.util.ConcurrentModificationException
// while(it.hasNext()) {
// String s = it.next();
// if(s.equals("aaa")) {
// list.add("ccc");
// }
// } // 2.加强for循环:java.util.ConcurrentModificationException
// for(String s : list) {
// if(s.equals("aaa")) {
// list.add("ccc");
// }
// } // 3.普通for循环可以,因为用的是:list.get(i),用 it.next()就出错
// 因为iterator源码里要比对一个东西
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.equals("aaa")) {
list.add("ccc");
}
}
System.out.println(list);
}
}

从上面的代码中可以发现,使用list.get(i)就可以完成需求,而使用it.next();就不行

我们看一下it.next()出了甚么问题

首先根据

Iterator<String> it = list.iterator();

我们追踪到list中的iterator的方法

package java.util;
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
  public Iterator<E> iterator() {
return new Itr();
}
  private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount; // prevent creating a synthetic constructor
Itr() {} public boolean hasNext() {
return cursor != size;
} @SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
} public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} @Override
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int size = ArrayList.this.size;
int i = cursor;
if (i < size) {
final Object[] es = elementData;
if (i >= es.length)
throw new ConcurrentModificationException();
for (; i < size && modCount == expectedModCount; i++)
action.accept(elementAt(es, i));
// update once at end to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
} final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

此时发现了一个CheckForComodification()函数,单独拿出来看一下

CheckForComodification()中我们看到抛出了ConcurrentModificationException的错误的可能性是 条件 modCount != expectedModCount 为真

package java.util;
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

好的我们继续debug,发现都是正常的,但是当if判断中条件为真,要执行

   list.add("ccc");

的时候,我们追踪到这个list中的add方法

package java.util;
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
  public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
}

我们可以看到modCount++,modCount的值被改变了,这就是modCount != expectedModCount 为真的情况

expected的意思是期望,也就是说期望值和实际值不同导致错误。

那么怎么解决,最简单就是不使用it.next()

而使用list.get()!

Java源码研究001:关于List的并发修改异常的更多相关文章

  1. java源码研究--List中的set和add方法区别

    在处理一道题目是,发现他们使用了List 中的set 方法,这个方法我平时很少用到,今天来研究一下,set和add的区别 add(int index,Object obj)方法与set(int ind ...

  2. java io 源码研究记录(一)

    Java IO 源码研究: 一.输入流 1  基类 InputStream 简介: 这是Java中所有输入流的基类,它是一个抽象类,下面我们简单来了解一下它的基本方法和抽象方法. 基本方法: publ ...

  3. 解密随机数生成器(二)——从java源码看线性同余算法

    Random Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术 ...

  4. 如何阅读Java源码?

    阅读本文大概需要 3.6 分钟. 阅读Java源码的前提条件: 1.技术基础 在阅读源码之前,我们要有一定程度的技术基础的支持. 假如你从来都没有学过Java,也没有其它编程语言的基础,上来就啃< ...

  5. springboot脚手架liugh-parent源码研究参考

    1. liugh-parent源码研究参考 1.1. 前言 这也是个开源的springboot脚手架项目,这里研究记录一些该框架写的比较好的代码段和功能 脚手架地址 1.2. 功能 1.2.1. 当前 ...

  6. Tika结合Tesseract-OCR 实现光学汉字识别(简体、宋体的识别率百分之百)—附Java源码、测试数据和训练集下载地址

     OCR(Optical character recognition) —— 光学字符识别,是图像处理的一个重要分支,中文的识别具有一定挑战性,特别是手写体和草书的识别,是重要和热门的科学研究方向.可 ...

  7. 从源码研究如何不重启Springboot项目实现redis配置动态切换

    上一篇Websocket的续篇暂时还没有动手写,这篇算是插播吧.今天讲讲不重启项目动态切换redis服务. 背景 多个项目或微服务场景下,各个项目都需要配置redis数据源.但是,每当运维搞事时(修改 ...

  8. 自己动手实现springboot运行时执行java源码(运行时编译、加载、注册bean、调用)

    看来断点.单步调试还不够硬核,根本没多少人看,这次再来个硬核的.依然是由于apaas平台越来越流行了,如果apaas平台选择了java语言作为平台内的业务代码,那么不仅仅面临着IDE外的断点.单步调试 ...

  9. 如何阅读Java源码 阅读java的真实体会

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心.   说到技术基础,我打个比 ...

随机推荐

  1. 【线程池】core与非core

    core和非core的区别: 当线程数小于core size时我们取task是这么取得: 小于时用poll并设置超时时间,否则用take阻塞等待 第二条件就出去了 没有拿到task的worker线程会 ...

  2. LaTeX学习路线

    LaTex源文件的基本结构 LaTex中的中文处理方法 LaTeX相关自学文档 LaTeX的字体字号设置 LaTeX文档的基本结构 LaTeX中的特殊字符 LaTeX中的插图 LaTeX中的表格 La ...

  3. CentOS下关于集群同步/LB/HA 的尝试

    Zookepper 集群同步 下载解压 wget http://apache.fayea.com/zookeeper/stable/zookeeper-3.4.8.tar.gz tar xvf zoo ...

  4. Fist—— 团队展示

    作业要求 软件工程1班 团队名称 Fist 这个作业的目标 团队合作开发项目,加强团队合作,进一步了解相应岗位. 作业正文 https://www.cnblogs.com/team4/p/137730 ...

  5. Spring Boot + Sharding-JDBC 读写分离

    本文使用 Sharding-JDBC 实现读写分离,基于 CentOS 7 + MySQL 5.7 一.MySQL 安装及配置 1.1 安装 依次执行命令: sudo wget -i -c http: ...

  6. Flink实战(102):配置(一)管理配置

    来源:http://www.54tianzhisheng.cn/2019/03/28/flink-additional-data/ 前言 如果你了解 Apache Flink 的话,那么你应该熟悉该如 ...

  7. django邮件发送

    需要一个邮箱,设置pop3 设置setting EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = ' ...

  8. 详解Hadoop3.x新特性功能-HDFS纠删码

    文章首发于微信公众号:五分钟学大数据 EC介绍 ​Erasure Coding 简称EC,中文名:纠删码 EC(纠删码)是一种编码技术,在HDFS之前,这种编码技术在廉价磁盘冗余阵列(RAID)中应用 ...

  9. [ASIS 2019]Unicorn shop

    点击进去之后是一个购买独角兽的界面,有四种类型的独角兽,前三种的价格比较便宜,最后的独角兽价格比较贵. 我们先尝试购买前三种独角兽,输入id,然后price输入9 然后就告诉我商品错了,可能复现靶场这 ...

  10. BUUOJ 杂项MISC(1)

    爱因斯坦 下载之后解压打开是一张爱因斯坦的图片,看来是图片隐写题 使用binwalk -e misc2.jpg 获得一个有flag.txt的压缩包,但是需要密码才能打开,猜想密码在图片里面,把图片丢进 ...