Java源码研究001:关于List的并发修改异常
这个就是实现一个简单的 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的并发修改异常的更多相关文章
- java源码研究--List中的set和add方法区别
在处理一道题目是,发现他们使用了List 中的set 方法,这个方法我平时很少用到,今天来研究一下,set和add的区别 add(int index,Object obj)方法与set(int ind ...
- java io 源码研究记录(一)
Java IO 源码研究: 一.输入流 1 基类 InputStream 简介: 这是Java中所有输入流的基类,它是一个抽象类,下面我们简单来了解一下它的基本方法和抽象方法. 基本方法: publ ...
- 解密随机数生成器(二)——从java源码看线性同余算法
Random Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术 ...
- 如何阅读Java源码?
阅读本文大概需要 3.6 分钟. 阅读Java源码的前提条件: 1.技术基础 在阅读源码之前,我们要有一定程度的技术基础的支持. 假如你从来都没有学过Java,也没有其它编程语言的基础,上来就啃< ...
- springboot脚手架liugh-parent源码研究参考
1. liugh-parent源码研究参考 1.1. 前言 这也是个开源的springboot脚手架项目,这里研究记录一些该框架写的比较好的代码段和功能 脚手架地址 1.2. 功能 1.2.1. 当前 ...
- Tika结合Tesseract-OCR 实现光学汉字识别(简体、宋体的识别率百分之百)—附Java源码、测试数据和训练集下载地址
OCR(Optical character recognition) —— 光学字符识别,是图像处理的一个重要分支,中文的识别具有一定挑战性,特别是手写体和草书的识别,是重要和热门的科学研究方向.可 ...
- 从源码研究如何不重启Springboot项目实现redis配置动态切换
上一篇Websocket的续篇暂时还没有动手写,这篇算是插播吧.今天讲讲不重启项目动态切换redis服务. 背景 多个项目或微服务场景下,各个项目都需要配置redis数据源.但是,每当运维搞事时(修改 ...
- 自己动手实现springboot运行时执行java源码(运行时编译、加载、注册bean、调用)
看来断点.单步调试还不够硬核,根本没多少人看,这次再来个硬核的.依然是由于apaas平台越来越流行了,如果apaas平台选择了java语言作为平台内的业务代码,那么不仅仅面临着IDE外的断点.单步调试 ...
- 如何阅读Java源码 阅读java的真实体会
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比 ...
随机推荐
- IDEA集成Docker插件后出现日志乱码的解决办法
修改IDEA的vmoptions文件 找到IDEA安装目录的bin目录,在idea.exe.vmoptions和idea64.exe.vmoptions文件中追加以下内容: -Dfile.encodi ...
- 电脑装MySQL免安装版配置失败提示系统错误2怎么解决?
一·准备工作 我下载安装的版本是:mysql-8.0.16-winx64(免安装版) 下载地址:https://www.mysql.com/ (官网地址)https://cdn2.lmonkey.co ...
- 红黑树、TreeMap、TreeSet
事先声明以下代码基于JDK1.8版本 参考资料 大部分图片引自https://www.jianshu.com/p/e136ec79235c侵删 https://www.cnblogs.com/skyw ...
- LeetCode 020 Valid Parentheses
题目描述:Valid Parentheses Given a string containing just the characters '(', ')', '{', '}', '[' and ']' ...
- Beta冲刺随笔——Day_Seven
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta 冲刺 这个作业的目标 团队进行Beta冲刺 作业正文 正文 其他参考文献 无 今日事今日毕 林涛: ...
- [从源码学设计]蚂蚁金服SOFARegistry之消息总线异步处理
[从源码学设计]蚂蚁金服SOFARegistry之消息总线异步处理 目录 [从源码学设计]蚂蚁金服SOFARegistry之消息总线异步处理 0x00 摘要 0x01 为何分离 0x02 业务领域 2 ...
- Mybatis报错invalid comparison: java.util.Date and java.lang.String
请求参数中两个属性确实都是date类型,数据库也确认是data类型,这个错误是因为 在这里把date类型的参数与单引号做了比较出现的,删除就可以正常运行了.
- PyQt(Python+Qt)学习随笔:QTableWidget设置项的setItem方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTableWidget表格部件中setItem用于在表格部件QTableWidget创建后,设定指 ...
- Flutter开发实战笔记
下载 https://flutter.cn/docs/get-started/install/macos#get-sdk 配置环境变量 export PATH="$PATH:[PATH_TO ...
- vue functional函数式组件
第1种写法 test.vue <template functional> <div class="test"> {{props.test.name}} &l ...