当前位置: 首页 > news >正文

for循环中list触发fast-fail或不触发的原理和方法

Iterable和Iterator

在这里插入图片描述
Iterator接口位于的位置是java.util.Iterator,它主要有两个抽象方法供子类实现。hasNext()用来判断还有没有数据可供访问,next()用来访问下一个数据。

集合Collection不是直接去实现Iterator接口,而是去实现Iterable接口。在这里插入图片描述
用这个Iterable接口的iterator()方法返回当前集合迭代器。
集合Collection体系的集合都得按照使用iterator()的方式返回可供遍历的迭代器iterator
在这里插入图片描述
集合使用Iterable接口的iterator()方法返回迭代器Iterator有很多好处。
在这里插入图片描述
比如有两个线程都需要使用迭代器进行遍历集合的操作,如果通过直接实现Iterator接口来拿迭代器。首先两者拿的是同一个迭代器,并且两者不同步,一个都遍历结束了,另一个都还没开始就无法遍历集合了,但是他本来循环从头开始遍历集合的所有数据的。

如果使用Iterable接口的iterator()方法返回迭代器Iterator,那两者获得的就是不同迭代器了,就互不影响,自己可以按照自己的进度遍历集合就行。
在这里插入图片描述


for-each就是迭代器的语法糖,增强版的 for 循环(也叫 “for-each” 循环)在 Java 中是一个特性,它允许你遍历任何实现了 Iterable 接口的集合或者数组。
要使用增强型 for 循环(也称为 for-each 循环)遍历一个集合,集合的类需要实现 java.lang.Iterable 接口。Iterable 接口定义了一个方法 iterator(),它返回一个 Iterator 对象,用于遍历集合的元素。

import java.util.Iterator;
import java.util.NoSuchElementException;// Iterable位于java.lang包下,不用显式import
public class MyCollection<T> implements Iterable<T> {private T[] elements;private int size;@SuppressWarnings("unchecked")public MyCollection(int capacity) {elements = (T[]) new Object[capacity];size = 0;}public void add(T element) {if (size < elements.length) {elements[size++] = element;} else {throw new IllegalStateException("Collection is full");}}// 当一个类要实现 Iterable 接口,它必须提供一个 iterator() 方法,该方法返回一个 Iterator 对象。@Overridepublic Iterator<T> iterator() {return new MyIterator();}private class MyIterator implements Iterator<T> {private int currentIndex = 0;@Overridepublic boolean hasNext() {return currentIndex < size;}@Overridepublic T next() {if (!hasNext()) {throw new NoSuchElementException();}return elements[currentIndex++];}}
}
MyCollection<String> collection = new MyCollection<>(10);collection.add("a");collection.add("b");collection.add("c");// 使用增强型 for 循环for (String element : collection) {System.out.println(element);}// 和增强for循环等价的显式迭代器循环// 当一个类实现了 Iterable 接口,它必须提供一个 iterator() 方法,该方法返回一个 Iterator 对象。// 这个 Iterator 对象实现了 hasNext() 和 next() 方法,用于遍历集合中的元素。// 下面的 iterator 是通过集合类实现的 Iterable 接口的 iterator() 方法获得的Iterator<String> iterator = collection.iterator();while (iterator.hasNext()) {String element = iterator.next();System.out.println(element);

快速失败机制的工作原理

fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件
Java中的集合类(如ArrayList、LinkedList、HashMap等)使用快速失败机制来检测在迭代过程中对集合的结构性修改。
工作原理如下:

  1. modCount:每个集合类都有一个modCount字段,用于记录集合结构性修改的次数。结构性修改是指添加或删除元素,改变集合的大小。
  2. 迭代器的expectedModCount:当创建迭代器时,迭代器会保存当前集合的modCount值到一个名为expectedModCount的字段中。
  3. 一致性检查:在每次调用迭代器的next()hasNext()方法时,迭代器首先会检查modCount是否与expectedModCount相同。如果不相同,说明集合在迭代过程中的结构被修改过,迭代器会抛出ConcurrentModificationException

总的来说:只要是涉及了改变ArrayList元素的个数的方法都会导致modCount的改变。当多线程环境下,由于expectedModCount与modCount的改变不同步,导致两者之间不等,从而产生fast-fail。

在这里插入图片描述
这里的抛出异常,停止执行就是fail-fast,就是当自己遇到无法处理的情况时的处理方式。

下面是ConcurrentModificationException异常的例子:

List<String> list = new ArrayList<>();
list.add("a");
Iterator<String> iterator = list.iterator();  // expectedModCount = modCount = 0
list.add("b");  // modCount = 1
iterator.next(); // expectedModCount != modCount, 抛出ConcurrentModificationException异常

for-each循环对集合进行增删也可能抛出异常,因为for-each在反编译下可以发现就是迭代器的语法糖,所以涉及到对迭代器的使用。

		List<String> collection = new ArrayList<>();collection.add("a");collection.add("b");// 使用增强型 for 循环for (String element : collection) {System.out.println(element);}// 和增强for循环等价的显式迭代器循环// 当一个类实现了 Iterable 接口,它必须提供一个 iterator() 方法,该方法返回一个 Iterator 对象。// 这个 Iterator 对象实现了 hasNext() 和 next() 方法,用于遍历集合中的元素。// 下面的 iterator 是通过集合类实现的 Iterable 接口的 iterator() 方法获得的Iterator<String> iterator = collection.iterator();while (iterator.hasNext()) {String element = iterator.next();if ("a".equals(element)) {collection.remove(element);}}

想要在循环时进行增删操作,也就是进行这类对集合结构性有影响的操作,就要保证数据隔离性,下面是三种数据隔离性的处理方式,本质都是复制东西,只是复制的东西有所不同。
在这里插入图片描述
写入时复制(copy-on-write, 简称COW)。
在这里插入图片描述

在这里插入图片描述
GC 代表 “Garbage Collection”(垃圾回收)。COW读操作时并没有加锁,这是为了提高读操作的性能,但是有缺点,比如读数据的时候可能读不到最新的数据。例如,线程1往集合里面add数据才增加了一半,线程2这时候就去读数据,那读到的就还是老数据。

在这里插入图片描述
这样的话就只有增删才需要开辟一个新数组,其他情况都是使用原数组引用来读取原数组。

// 可以像使用普通的 ArrayList 一样使用 CopyOnWriteArrayList(写入时复制),并且可以通过 List 接口来引用它List<String> cowList = new CopyOnWriteArrayList<>();cowList.add("a");cowList.add("b");cowList.add("c");Iterator<String> iterator = cowList.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}cowList.remove("b");Iterator<String> iterator2 = cowList.iterator();while (iterator2.hasNext()) {System.out.println(iterator2.next());}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • windows@windows设备之间远程命令行控制方案@windows设备间使用OpenSSH
  • C语言力扣刷题12——合并区间[排序]
  • 继承关系中的访问控制
  • 实战 | YOLOv8使用TensorRT加速推理教程(步骤 + 代码)
  • Python股票计算小程序(字符串格式化练习)
  • UE5 04-重新加载当前场景
  • c++内存管理(上)
  • 论文辅助笔记:ST-LLM
  • UE5 修改项目名称 类的名称
  • 了解Adam和RMSprop优化算法
  • 基于深度学习的图像补全
  • elementPlus-vue3-ts表格单选和双选实现方式
  • 【C++】C++入门基础--命名空间,缺省参数,函数重载
  • RTOS系统 -- 调试大法之FreeRTOS在M4上实现coredump功能
  • Spark操作Excel最佳实践
  • CentOS 7 修改主机名
  • Docker下部署自己的LNMP工作环境
  • mysql innodb 索引使用指南
  • node学习系列之简单文件上传
  • Python 基础起步 (十) 什么叫函数?
  • Python学习笔记 字符串拼接
  • Vue.js源码(2):初探List Rendering
  • vue中实现单选
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 面试遇到的一些题
  • 使用Swoole加速Laravel(正式环境中)
  • 数据结构java版之冒泡排序及优化
  • 思考 CSS 架构
  • 微信小程序填坑清单
  • 小试R空间处理新库sf
  • 一个SAP顾问在美国的这些年
  • Java数据解析之JSON
  • ​水经微图Web1.5.0版即将上线
  • #AngularJS#$sce.trustAsResourceUrl
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (不用互三)AI绘画工具应该如何选择
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (六)激光线扫描-三维重建
  • (十六)Flask之蓝图
  • (四)React组件、useState、组件样式
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .net的socket示例
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • @AliasFor 使用
  • @Autowired和@Resource的区别
  • @Value获取值和@ConfigurationProperties获取值用法及比较(springboot)
  • @vueup/vue-quill使用quill-better-table报moduleClass is not a constructor
  • [12] 使用 CUDA 加速排序算法
  • [240607] Jina AI 发布多模态嵌入模型 | PHP 曝新漏洞 | TypeScript 5.5 RC 发布公告
  • [ASP.NET 控件实作 Day7] 设定工具箱的控件图标
  • [AX]AX2012 AIF(四):文档服务应用实例
  • [C/C++] C/C++中数字与字符串之间的转换
  • [C++打怪升级]--学习总目录
  • [Deepin] 简单使用 RustDesk 实现远程访问Deepin