今天读了JDK1.8源码,知道了并行迭代器Spliterator
在JDK1.8的ArrayList里面偶然看到了這個(gè)內(nèi)部類,同時(shí)對(duì)比了1.7的版本,發(fā)現(xiàn)1.7并沒有這后面的東西, 隨著好奇心,就搜了一下下,發(fā)現(xiàn)很有意思~? 也查了一些資料,如下總結(jié):
Spliterator是什么?
Spliterator是一個(gè)可分割迭代器(splitable iterator),可以和iterator順序遍歷迭代器一起看。jdk1.8發(fā)布后,對(duì)于并行處理的能力大大增強(qiáng),Spliterator就是為了并行遍歷元素而設(shè)計(jì)的一個(gè)迭代器,jdk1.8中的集合框架中的數(shù)據(jù)結(jié)構(gòu)都默認(rèn)實(shí)現(xiàn)了spliterator,后面我們也會(huì)結(jié)合ArrayList中的spliterator()一起解析。
Spliterator內(nèi)部結(jié)構(gòu)
//單個(gè)對(duì)元素執(zhí)行給定的動(dòng)作,如果有剩下元素未處理返回true,否則返回false boolean tryAdvance(Consumer<? super T> action);//對(duì)每個(gè)剩余元素執(zhí)行給定的動(dòng)作,依次處理,直到所有元素已被處理或被異常終止。默認(rèn)方法調(diào)用tryAdvance方法 default void forEachRemaining(Consumer<? super T> action) {do { } while (tryAdvance(action)); }//對(duì)任務(wù)分割,返回一個(gè)新的Spliterator迭代器 Spliterator<T> trySplit();//用于估算還剩下多少個(gè)元素需要遍歷 long estimateSize();//當(dāng)?shù)鲹碛蠸IZED特征時(shí),返回剩余元素個(gè)數(shù);否則返回-1 default long getExactSizeIfKnown() {return (characteristics() & SIZED) == 0 ? -1L : estimateSize(); }//返回當(dāng)前對(duì)象有哪些特征值 int characteristics();//是否具有當(dāng)前特征值 default boolean hasCharacteristics(int characteristics) {return (characteristics() & characteristics) == characteristics; } //如果Spliterator的list是通過Comparator排序的,則返回Comparator //如果Spliterator的list是自然排序的 ,則返回null //其他情況下拋錯(cuò) default Comparator<? super T> getComparator() {throw new IllegalStateException(); }JDK8源碼內(nèi)的ArrayList中的ArrayListSpliterator
static final class ArrayListSpliterator<E> implements Spliterator<E> {//用于存放ArrayList對(duì)象private final ArrayList<E> list;//起始位置(包含),advance/split操作時(shí)會(huì)修改private int index;//結(jié)束位置(不包含),-1 表示到最后一個(gè)元素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;}//獲取結(jié)束位置(存在意義:首次初始化石需對(duì)fence和expectedModCount進(jìn)行賦值)private int getFence() {int hi;ArrayList<E> lst;//fence<0時(shí)(第一次初始化時(shí),fence才會(huì)小于0):if ((hi = fence) < 0) {//list 為 null時(shí),fence=0if ((lst = list) == null)hi = fence = 0;else {//否則,fence = list的長度。expectedModCount = lst.modCount;hi = fence = lst.size;}}return hi;}//分割list,返回一個(gè)新分割出的spliterator實(shí)例public ArrayListSpliterator<E> trySplit() {//hi為當(dāng)前的結(jié)束位置//lo 為起始位置//計(jì)算中間的位置int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;//當(dāng)lo>=mid,表示不能在分割,返回null//當(dāng)lo<mid時(shí),可分割,切割(lo,mid)出去,同時(shí)更新index=midreturn (lo >= mid) ? null :new ArrayListSpliterator<E>(list, lo, index = mid, expectedModCount);}//返回true 時(shí),只表示可能還有元素未處理//返回false 時(shí),沒有剩余元素處理了。。。public boolean tryAdvance(Consumer<? super E> action) {if (action == null)throw new NullPointerException();//hi為當(dāng)前的結(jié)束位置//i 為起始位置int hi = getFence(), i = index;//還有剩余元素未處理時(shí)if (i < hi) {//處理i位置,index+1index = i + 1;@SuppressWarnings("unchecked") E e = (E)list.elementData[i];action.accept(e);//遍歷時(shí),結(jié)構(gòu)發(fā)生變更,拋錯(cuò)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) {//當(dāng)fence<0時(shí),表示fence和expectedModCount未初始化,可以思考一下這里能否直接調(diào)用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];//調(diào)用action.accept處理元素action.accept(e);}//遍歷時(shí)發(fā)生結(jié)構(gòu)變更時(shí)拋出異常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;} }以上為源碼講解部分,大意是說,這個(gè)就是用來多線程并行迭代的迭代器,這個(gè)迭代器的主要作用就是把集合分成了好幾段,每個(gè)線程執(zhí)行一段,因此是線程安全的。基于這個(gè)原理,以及modCount的快速失敗機(jī)制,如果迭代過程中集合元素被修改,會(huì)拋出異常。
我們?cè)O(shè)計(jì)一個(gè)測(cè)試用例:創(chuàng)建一個(gè)長度為100的list,如果下標(biāo)能被10整除,則該位置數(shù)值跟下標(biāo)相同,否則值為aaaa。然后多線程遍歷list,取出list中的數(shù)值(字符串a(chǎn)aaa不要)進(jìn)行累加求和。
測(cè)試代碼如下:
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();/*** 多線程計(jì)算list中數(shù)值的和 測(cè)試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("結(jié)果為:" + count);}class MyThread extends Thread {@SuppressWarnings("unchecked")@Overridepublic void run() {final String threadName = Thread.currentThread().getName();System.out.println("線程" + threadName + "開始運(yùn)行-----");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("數(shù)值:" + num + "------" + threadName);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}});System.out.println("線程" + threadName + "運(yùn)行結(jié)束-----");}}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();} }運(yùn)行結(jié)果為:
從結(jié)果可以看出,四個(gè)線程遍歷沒有產(chǎn)生并發(fā)問題,
本文參考:https://www.cnblogs.com/nevermorewang/p/9368431.html??????? 謝謝~
總結(jié)
以上是生活随笔為你收集整理的今天读了JDK1.8源码,知道了并行迭代器Spliterator的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: enum操作--获取枚举里的最大值
- 下一篇: 气象数据网址