之前的时候看集合部分源码没看完,今天又翻了一下,看到了个东西spliterator,感觉挺陌生。查了一下,网上解读源码的挺多,但没有使用的例子,于是看了下代码,准备自己写个例子试试。
源码部分,灵小帝的博客已经说的很清楚了,摘抄如下:
--------------------------------------------------------------------------------------------------------------------------
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();
}
  特征值其实就是为表示该Spliterator有哪些特性,用于可以更好控制和优化Spliterator的使用。关于获取比较器getComparator这一个方法,目前我还没看到具体使用的地方,所以可能理解有些误差。特征值如下:(部分属于猜测)
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的modCount
private 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=0
if ((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=mid
return (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+1
index = 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 loop
ArrayList<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;
}
else
mc = 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() {
//打上特征值:、可以返回size
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}
--------------------------------------------------------------------------------------------------------------------------
  以上为源码讲解部分,大意是说,这个就是用来多线程并行迭代的迭代器,这个迭代器的主要作用就是把集合分成了好几段,每个线程执行一段,因此是线程安全的。基于这个原理,以及modCount的快速失败机制,如果迭代过程中集合元素被修改,会抛出异常。
  我们设计一个测试用例:创建一个长度为100的list,如果下标能被10整除,则该位置数值跟下标相同,否则值为aaaa。然后多线程遍历list,取出list中的数值(字符串aaaa不要)进行累加求和。
测试代码如下:

public class Atest {
AtomicInteger count = new AtomicInteger(0);
List<String> strList = createList();
Spliterator spliterator = strList.spliterator(); /**
* 多线程计算list中数值的和
* 测试spliterator遍历
*/
@Test
public 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{
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println("线程"+threadName+"开始运行-----");
spliterator.trySplit().forEachRemaining(new Consumer() {
@Override
public 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();
}
}
  输出结果:

  可以看到,有4个线程执行了该方法,并得到了正确的结果,并发遍历执行没有问题。

 
 
 

最新文章

  1. 分治法解决合并排序(c++和Java源代码)
  2. javascript--Object
  3. js中控制小数点的显示位数的技术整理
  4. SUSE Linux下新建Weblogic 10.3非admin服务
  5. java面向对象编程——第六章 数组
  6. Python学习路程day6
  7. 开源项目 Modbus C#实现
  8. HDU-4681 String 枚举+DP
  9. Android打开外部DB文件
  10. bootstarp基本模板
  11. C# - Environment类,获取桌面的路径
  12. Android - 读取文件存储的数据
  13. Python:SQLMap源码精读—基于时间的盲注(time-based blind)
  14. 推荐安全且匿名的邮箱 ProtonMail -- PGP算法
  15. Pandas 基础(16) - Holidays
  16. opencv的安装
  17. 软工网络15团队作业4——Alpha阶段敏捷冲刺
  18. SSM框架、Druid连接池实现多数据源配置(已上线使用)
  19. scrapy框架之CrawlSpider操作
  20. 1.1环境的准备(一)之Python解释器的安装

热门文章

  1. bzoj 4624 农场种植 fft
  2. 有关javamelody的配置
  3. 使用SpringMVC解决Ajax跨域问题
  4. Django-urls路由分发
  5. [Leetcode Week6]Linked List Cycle II
  6. [Leetcode Week3]Clone Graph
  7. UVA 10385 Duathlon
  8. (接口自动化)Python3操作MySQL数据库
  9. Hadoop运维记录系列
  10. vCard