今天读了JDK1.8源码,知道了并行迭代器Spliterator

在JDK1.8的ArrayList里面偶然看到了这个内部类,同时对比了1.7的版本,发现1.7并没有这后面的东西, 随着好奇心,就搜了一下下,发现很有意思~  也查了一些资料,如下总结:

Spliterator是什么

  Spliterator是一个可分割迭代器(splitable iterator),可以和iterator顺序遍历迭代器一起看。jdk1.8发布后,对于并行处理的能力大大增强,Spliterator就是为了并行遍历元素而设计的一个迭代器,jdk1.8中的集合框架中的数据结构都默认实现了spliterator,后面我们也会结合ArrayList中的spliterator()一起解析。

Spliterator内部结构

//单个对元素执行给定的动作,如果有剩下元素未处理返回true,否则返回false
boolean tryAdvance(Consumer<? super T> action);//对每个剩余元素执行给定的动作,依次处理,直到所有元素已被处理或被异常终止。默认方法调用tryAdvance方法
default void forEachRemaining(Consumer<? super T> action) {do { } while (tryAdvance(action));
}//对任务分割,返回一个新的Spliterator迭代器
Spliterator<T> trySplit();//用于估算还剩下多少个元素需要遍历
long estimateSize();//当迭代器拥有SIZED特征时,返回剩余元素个数;否则返回-1
default long getExactSizeIfKnown() {return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
}//返回当前对象有哪些特征值
int characteristics();//是否具有当前特征值
default boolean hasCharacteristics(int characteristics) {return (characteristics() & characteristics) == characteristics;
}
//如果Spliterator的list是通过Comparator排序的,则返回Comparator
//如果Spliterator的list是自然排序的 ,则返回null
//其他情况下抛错
default Comparator<? super T> getComparator() {throw new IllegalStateException();
}

JDK8源码内的ArrayList中的ArrayListSpliterator

static final class ArrayListSpliterator<E> implements Spliterator<E> {//用于存放ArrayList对象private final ArrayList<E> list;//起始位置(包含),advance/split操作时会修改private int index;//结束位置(不包含),-1 表示到最后一个元素private int fence;//用于存放list的modCountprivate int expectedModCount;ArrayListSpliterator(ArrayList<E> list, int origin, int fence,int expectedModCount) {this.list = list;this.index = origin;this.fence = fence;this.expectedModCount = expectedModCount;}//获取结束位置(存在意义:首次初始化石需对fence和expectedModCount进行赋值)private int getFence() {int hi;ArrayList<E> lst;//fence<0时(第一次初始化时,fence才会小于0):if ((hi = fence) < 0) {//list 为 null时,fence=0if ((lst = list) == null)hi = fence = 0;else {//否则,fence = list的长度。expectedModCount = lst.modCount;hi = fence = lst.size;}}return hi;}//分割list,返回一个新分割出的spliterator实例public ArrayListSpliterator<E> trySplit() {//hi为当前的结束位置//lo 为起始位置//计算中间的位置int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;//当lo>=mid,表示不能在分割,返回null//当lo<mid时,可分割,切割(lo,mid)出去,同时更新index=midreturn (lo >= mid) ? null :new ArrayListSpliterator<E>(list, lo, index = mid,                                         expectedModCount);}//返回true 时,只表示可能还有元素未处理//返回false 时,没有剩余元素处理了。。。public boolean tryAdvance(Consumer<? super E> action) {if (action == null)throw new NullPointerException();//hi为当前的结束位置//i 为起始位置int hi = getFence(), i = index;//还有剩余元素未处理时if (i < hi) {//处理i位置,index+1index = i + 1;@SuppressWarnings("unchecked") E e = (E)list.elementData[i];action.accept(e);//遍历时,结构发生变更,抛错if (list.modCount != expectedModCount)throw new ConcurrentModificationException();return true;}return false;}//顺序遍历处理所有剩下的元素public void forEachRemaining(Consumer<? super E> action) {int i, hi, mc; // hoist accesses and checks from loopArrayList<E> lst; Object[] a;if (action == null)throw new NullPointerException();if ((lst = list) != null && (a = lst.elementData) != null) {//当fence<0时,表示fence和expectedModCount未初始化,可以思考一下这里能否直接调用getFence(),嘿嘿?if ((hi = fence) < 0) {mc = lst.modCount;hi = lst.size;}elsemc = expectedModCount;if ((i = index) >= 0 && (index = hi) <= a.length) {for (; i < hi; ++i) {@SuppressWarnings("unchecked") E e = (E) a[i];//调用action.accept处理元素action.accept(e);}//遍历时发生结构变更时抛出异常if (lst.modCount == mc)return;}}throw new ConcurrentModificationException();}public long estimateSize() {return (long) (getFence() - index);}public int characteristics() {//打上特征值:、可以返回sizereturn Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;}
}

以上为源码讲解部分,大意是说,这个就是用来多线程并行迭代的迭代器,这个迭代器的主要作用就是把集合分成了好几段,每个线程执行一段,因此是线程安全的。基于这个原理,以及modCount的快速失败机制,如果迭代过程中集合元素被修改,会抛出异常。

  我们设计一个测试用例:创建一个长度为100的list,如果下标能被10整除,则该位置数值跟下标相同,否则值为aaaa。然后多线程遍历list,取出list中的数值(字符串aaaa不要)进行累加求和。

测试代码如下:

package com.turingschool.demo.ds;import java.util.ArrayList;
import java.util.List;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.regex.Pattern;import org.junit.Test;public class Atest {AtomicInteger count = new AtomicInteger(0);List<String> strList = createList();Spliterator spliterator = strList.spliterator();/*** 多线程计算list中数值的和 测试spliterator遍历*/@Testpublic void mytest() {for (int i = 0; i < 4; i++) {new MyThread().start();}try {Thread.sleep(15000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("结果为:" + count);}class MyThread extends Thread {@SuppressWarnings("unchecked")@Overridepublic void run() {final String threadName = Thread.currentThread().getName();System.out.println("线程" + threadName + "开始运行-----");spliterator.trySplit().forEachRemaining(new Consumer() {@Overridepublic void accept(Object o) {if (isInteger((String) o)) {int num = Integer.parseInt(o + "");count.addAndGet(num);System.out.println("数值:" + num + "------" + threadName);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}});System.out.println("线程" + threadName + "运行结束-----");}}private List<String> createList() {List<String> result = new ArrayList<>();for (int i = 0; i < 100; i++) {if (i % 10 == 0) {result.add(i + "");} else {result.add("aaa");}}return result;}public static boolean isInteger(String str) {Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");return pattern.matcher(str).matches();}
}

运行结果为:

从结果可以看出,四个线程遍历没有产生并发问题,

本文参考:https://www.cnblogs.com/nevermorewang/p/9368431.html        谢谢~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/413563.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

牛客网挑战赛24 青蛙(BFS)

链接&#xff1a;https://www.nowcoder.com/acm/contest/157/E来源&#xff1a;牛客网 有一只可爱的老青蛙&#xff0c;在路的另一端发现了一个黑的东西&#xff0c;想过去一探究竟。于是便开始踏上了旅途 一直这个小路上有很多的隧道&#xff0c;从隧道的a进入&#xff0c;会从…

20.pipe

pipe相当于angular1里面的filter 做一些格式转换啊&#xff0c;或者从一个数组里面选取一个元素等等 只要你愿意可以定义很复杂的内容‘’ 我们先看看 angular2 里面自带的一些pipe 我们去我们的week3 下的problem-list下 我们到html里面 之前是这样的 之后是这样的 我们再写三…

Redis内部数据结构-跳跃表

今天学习了跳跃表&#xff0c;记录一下下~ 一、跳跃表简介 跳跃表是一种随机化数据结构&#xff0c;基于并联的链表&#xff0c;其效率可以比拟平衡二叉树&#xff0c;查找、删除、插入等操作都可以在对数期望时间内完成&#xff0c;对比平衡树&#xff0c;跳跃表的实现要简…

Mybatis源码学习笔记

Mybatis核心概念: Configuration : 管理 mysql-config.xml 全局配置关系类 SqlSessionFactory: Session 管理工厂接口 Session: SqlSession 是一个面向用户&#xff08;程序员&#xff09;的接口。SqlSession 中提供了很多操作数据库的方法 Executor : 执行器是一个接口…

JQData数据提取及MySQL简单操作——基于Python

JQData平台真的挺不错&#xff0c;平台数据可以免费使用一年&#xff0c;满足绝大多数人需求&#xff0c;具体账号获取请自行百度哟~ 因需要高频数据而Wind也只给近三年&#xff0c;再要还得购&#xff0c;&#xff0c;机缘遇到这一平台&#xff0c;获得了账号试用很不错&#…

JVM模型学习笔记

JVM由三个主要的子系统构成 1. 运行时数据区&#xff08;内存结构&#xff09;: 运行时数据区也是JVM的核心部分 内存数据区又分&#xff1a;堆、java栈、本地方法栈、程序计数器、方法区 1.1 本地方法栈(线程私有)&#xff1a; 登记native方法&#xff0c;在Execution Eng…

tomcat 设置虚拟路径的4种方法

通常使用方法1或者方法2 方法1 &#xff08;添加配置文件&#xff09;&#xff1a;推荐使用&#xff0c;不需要重启服务器 在Tomcat根目录下的/conf/Catalina/localhost/ 路径下新建一个filename.xml&#xff0c;并在该xml中编写语句 即可创建虚拟站点&#xff0c;虚拟站点名为…

sharding-sphere按月动态分表

公司有个记录表&#xff0c;每天有几百万的数据&#xff0c;所以我决定按月把他分下表。 用spring整合的。 首先&#xff0c;sharding-sphere不支持自动创建表&#xff0c;所以我提前创建了两年的表&#xff0c;命名规则 logicTableName _2019_06 以下是官方文档上面的分片…

大厂Java岗面试心得记录

最近裸辞&#xff0c;面了几家大厂&#xff0c;offer率高达100% 哈哈&#xff0c;然后发现选公司也是一件难事。 废话不多说&#xff0c;分享一下&#xff0c;我遇到的面试题&#xff0c;大概有以下这些&#xff1a; JVM: 1.JVM有哪些区域&#xff1f; 2.堆和栈分别说说内部东…

原生Js 两种方法实现页面关键字高亮显示

方法一 依靠正则表达式修改 1.获取obj的html 2.统一替换html标签 3.替换要修改的关键字 4.再把html标签修改回去 不足就是如果查找的关键字跟替换的标签一样就有冲突了 <!DOCTYPE HTML> <html lang"en"> <meta http-equiv"Content-Type" co…

SpringBoot启动报错java.nio.charset.MalformedInputException: Input length = 2解决方案

最近新搭的一个项目&#xff0c;启动时&#xff0c;会报MalformedInputException这个异常&#xff0c; 百度了很久&#xff0c;网上说的千篇一律&#xff0c; 有的说&#xff0c;把yml复制到txt再复制回来 有的说&#xff0c;设置eclipse的utf-8环境 这些根本没有根治这个问…

IDEA主题设置与eclipse代码风格一致

习惯了用eclipse的你&#xff0c;是不是转到用idea特别不习惯&#xff0c;没有关系&#xff0c; 我们可以把idea的代码风格改成eclipse的&#xff0c;快捷键也换成eclipse的。 下载这个jar包&#xff0c;导入settings文件即可 下载地址 : https://download.csdn.net/download…

浅谈分布式锁

概述 为了防止分布式系统中的多个进程之间相互干扰&#xff0c;我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。 为什么要使用分布式锁 成员变量 A 存在 JVM1、JVM2、JVM3 三个 JVM 内存中 成员变量 A 同时都会在 JVM …

[css] 说说sroll-snap-type属性的运用场景有哪些?相关联的属性还有哪些?

[css] 说说sroll-snap-type属性的运用场景有哪些&#xff1f;相关联的属性还有哪些&#xff1f; 使用 sroll-snap-type 优化滚动 根据 CSS Scroll Snap Module Level 1 规范&#xff0c;CSS 新增了一批能够控制滚动的属性&#xff0c;让滚动能够在仅仅通过 CSS 的控制下&#…

简单的一个月之设计实现内容1

需求:简单的新闻管理系统,实现简单的增删改查功能 1.数据库表的建立 ID非空,数据类型看着给 2.写实体(entity)News.java 要与数据库中的字段相对应,(id,optimistic我没写,问题不大)1 package com.pay.boss.entity; //封装好的entity包,直接引用2 3 import java.util.Date; …

分享一个有趣的网站“让我帮你百度一下“

如何解决同事的弱智问题&#xff0c;分享一个有趣的网站 日常工作中&#xff0c;总有些人会问你一些弱智的问题 你只需要三步就可以完美解决: 1.打开这个链接: 让我帮你百度一下 2.输入他的问题、点回车 3.复制结果链接甩到他的脸上_ hahahhahahaha 这样就解决了一切烦恼&a…

SQL Server2014 SP2新增的数据库克隆功能

SQL Server2014 SP2新增的数据库克隆功能 原文:SQL Server2014 SP2新增的数据库克隆功能SQL Server2014 SP2新增的数据库克隆功能 创建测试库 --创建测试数据库 create database testtestuse testtest go --创建表 create table testtest(id int ,name varchar(20)) --插入数据…

工作328:uni-两个页面对象传递

getDetailList(record){console.log(record)uni.navigateTo({url:../formdaliyList/formdaliyList?recordencodeURIComponent(JSON.stringify(record))})},onLoad(e){/* JSON.parse() */let obj JSON.parse(decodeURIComponent(e.record));console.log(obj)},

vue-js 特殊变量$event常识

背景 如果我们要阻止默认事件&#xff0c;在 chrome 等浏览器中&#xff0c;我们可能要写一个&#xff1a; event.preventDefault(); 而在 IE 中&#xff0c;我们则需要写&#xff1a; event.returnValue false; jquery &#xff0c;跨浏览器的实现&#xff0c;我们统一只…

七、线性表的链式存储结构

1、问题引入 开发数组类模板的原因在于&#xff1a;在创建基于顺序存储结构的线性表时&#xff0c;发现这样的线性表可能被误用&#xff0c;因为重载了数组访问操作符&#xff0c;使用时跟数组类似&#xff0c;但是线性表和数组有很大的区别&#xff0c;所以激发了新的需求&…