java 数据结构之arraylist Spliterator 使用和源码解析
Posted xiaoliuliu2050
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 数据结构之arraylist Spliterator 使用和源码解析相关的知识,希望对你有一定的参考价值。
以下是一个案例来使用spliterator :
首先需要定义一个线程,然后需要将拆分后的迭代器传入该线程。执行start()方法让实现的run()方法进入就绪状态等待调用
自定义线程代码如下:
1 package com.FM.ArrayListStudy;
2
3 import java.util.Spliterator;
4 import java.util.function.Consumer;
5
6 /**
7 * 内部类,线程调用
8 */
9 public class MyThread4Spliterator<T> extends Thread
10 // 寄存变量
11 private Spliterator<T> list;
12
13 // 构造 - 传递参数
14 public MyThread4Spliterator(Spliterator<T> list)
15 setList(list);
16
17
18 // 线程调用run
19 @Override
20 public void run()
21 Spliterator<T> list2 = getList();
22 list2.forEachRemaining(new Consumer<T>()
23
24 @Override
25 public void accept(T t)
26 System.out.println(Thread.currentThread().getName()+" === "+t);
27
28
29 );
30
31
32 public Spliterator<T> getList()
33 return list;
34
35
36 public void setList(Spliterator<T> list)
37 this.list = list;
38
39
定义并拆分迭代器代码如下,需要注意拆分规则
1 package com.FM.ArrayListStudy;
2
3 import java.util.ArrayList;
4 import java.util.Spliterator;
5
6 public class SpliteratorInArrayListStudy
7 public static void main(String[] args)
8 // 初始化list
9 ArrayList<Integer> list = new ArrayList<Integer>();
10 for (int i = 0; i < 20; i++)
11 list.add(i + 1);
12
13 //四线程均分配比方式
14 Spliterator<Integer> spliterator01 = list.spliterator(); //01中有20个元素
15 Spliterator<Integer> spliterator02 = spliterator01.trySplit(); //01中有10个元素,02中有10个元素
16 Spliterator<Integer> spliterator03 = spliterator01.trySplit(); //01中有5个元素,02中有10个元素,03中有5个元素
17 Spliterator<Integer> spliterator04 = spliterator02.trySplit(); //01中有5个元素,02中有5个元素,03中有5个元素,04中有5个元素
18 MyThread4Spliterator<Integer> t01 = new MyThread4Spliterator<Integer>(spliterator01);
19 MyThread4Spliterator<Integer> t02 = new MyThread4Spliterator<Integer>(spliterator02);
20 MyThread4Spliterator<Integer> t03 = new MyThread4Spliterator<Integer>(spliterator03);
21 MyThread4Spliterator<Integer> t04 = new MyThread4Spliterator<Integer>(spliterator04);
22 t01.setName("001");
23 t02.setName("002");
24 t03.setName("003");
25 t04.setName("004");
26
27 t01.start();
28 t02.start();
29 t03.start();
30 t04.start();
31
32
运行结果:
Spliterator为jdk1.8新增接口,也是一个迭代器实现,从名称可以看出来,Spliterator是一个可分割的迭代器,用来分割和迭代给定源的元素,这里的源可以是collection,array和io等。
该对象可以使用trySplit进行迭代器拆分,每次拆分后的迭代器接近上一次的二分之一。
这是官方对于大数据量数组多线程遍历加工的一种趋势性指引。
方法解析:
int characteristics();
返回当前实例的一个特征集,这个特征值集包括:
//表示迭代器需要按照其原始顺序迭代其中元素的
public static final int ORDERED = 0x00000010;
//迭代器中的元素是没有重复的
public static final int DISTINCT = 0x00000001;
//迭代器是按照某种方式排序的顺序迭代其中元素的
public static final int SORTED = 0x00000004;
//表示迭代器将要迭代的元素的个数是可计数的,有界的
public static final int SIZED = 0x00000040;
//迭代器迭代的元素是没有值为`null`的
public static final int NONNULL = 0x00000100;
//迭代器迭代的元素是不可改变的,也不可以增加、替换和删除
public static final int IMMUTABLE = 0x00000400;
//表示迭代器的数据源是线程安全的
public static final int CONCURRENT = 0x00001000;
//表示当前迭代器所有的子迭代器(直接的或者间接的),都是`SIZED`和`SUBSIZED`的
public static final int SUBSIZED = 0x00004000;
例如一个Collection实例的spliterator会报告一个SIZED的特征,一个Set实例会报告一个DISTINCT特征,等。
如果一个迭代器没有报告IMMUTABLE或者CONCURRENT特征时,其绑定数据源后会检查数据源的结构化改动。后绑定的迭代器是绑定数据源发生在其第一次遍历、第一次拆分、第一次查询大小时,而不是在迭代器创建后立刻绑定数据源。和其它迭代器一样,绑定前对源的修改可以反应在迭代器遍历过程中,而绑定后的对源的修改会导致ConcurrentModificationException异常。
Spliterator的批量遍历方法(forEachRemaining())可以遍历所有元素之后优化遍历并检对源的结构化修改,而不是逐个检查元素并立即抛出失败。
Spliterator提供了estimateSize()方法用来估算迭代器中剩余元素的数量,理想情况下,它能够准确的计算迭代器中能够成功迭代的元素的数量,即使是在不准切的时候,其结果依然能够为对迭代器的下一步操作,如是直接迭代剩余元素还是继续分割迭代器提供依据。
尽管Spliterator为并发迭代提供了入口,但它依旧是线程不安全的。相反,spliterator的并发实现必须保证其在同一个时刻只有一个线程访问。调用trySplit()的线程可能会后续将迭代器交给其他线程进行迭代或者继续分割,并发的分割或者迭代同一个迭代器会导致不确定的结果。如果需要将迭代器由一个线程递交给另一个线程,需要保证递交前没有使用tryAdvance()消费任何元素。
Spliterator为原始类型中的int、long、double提供了专门的子类并默认实现了tryAdvance(java.util.function.Consumer) 和forEachRemaining(java.util.function.Consumer)。
方法
estimateSize()
估计当前Spliterator实例中将要迭代的元素的数量,如果数量是无限的、未知的或者计算数量的花销太大,则返回Long.MAX_VALUE
trySplit()
分割迭代器,没调用一次,将原来的迭代器等分为两份,并返回索引靠前的那一个子迭代器。
forEachRemaining(Consumer<? super E> action)
通过action批量消费所有的未迭代的数据。
以ArrayListSpliterator为例说明Spliterator的实现:
static final class ArrayListSpliterator<E> implements Spliterator<E>
private final ArrayList<E> list;
private int index; // current index, modified on advance/split
private int fence; // -1 until used; then one past last index
private int expectedModCount; // initialized when fence set
/** Create new spliterator covering the given range */
ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
int expectedModCount)
this.list = list; // OK if null unless traversed
this.index = origin;
this.fence = fence;
this.expectedModCount = expectedModCount;
private int getFence() // initialize fence to size on first use
int hi; // (a specialized variant appears in method forEach)
ArrayList<E> lst;
if ((hi = fence) < 0)
if ((lst = list) == null)
hi = fence = 0;
else
expectedModCount = lst.modCount;
hi = fence = lst.size;
return hi;
public ArrayListSpliterator<E> trySplit()
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid) ? null : // divide range in half unless too small
new ArrayListSpliterator<E>(list, lo, index = mid,
expectedModCount);
public boolean tryAdvance(Consumer<? super E> action)
if (action == null)
throw new NullPointerException();
int hi = getFence(), i = index;
if (i < hi)
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)
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(e);
if (lst.modCount == mc)
return;
throw new ConcurrentModificationException();
public long estimateSize()
return (long) (getFence() - index);
public int characteristics()
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
以上是关于java 数据结构之arraylist Spliterator 使用和源码解析的主要内容,如果未能解决你的问题,请参考以下文章
String split 转 arrayList,java.lang.UnsupportedOperationException