Java的Spliterator使用方式


Spliterator接口包含的方法:

boolean tryAdvance(Consumer action); 單個對下一個元素執行給定的動作,如果有剩下元素未處理,執行則返回true,否則返回false

default void forEachRemaining(Consumer action) 對剩余元素依次執行action函數

Spliterator trySplit(); 將一個Spliterator分割成多個Spliterator並返回。分割的Spliterator被用於每個子線程進行處理,從而達到並發處理的效果。

long estimateSize(); 該方法返回值並不會對代碼正確性產生影響,但是會影響代碼的執行線程數,后續會介紹一下

int characteristics(); 給出stream流具有的特性,不同的特性,不僅是會對流的計算有優化作用,更可能對計算結果會產生影響。

// 表明元素是有序的,如果是此特征值,那么trySplit分割之后的元素是有序的,tryAdvance處理元素也是有序的,forEachRemaining處理元素也是有序的。如果Collection#iterator是有序的,那么Collection也是有序的。List的遍歷順序是按照索引順序,HashSet是無序的
public static final int ORDERED    = 0x00000010;
// 表明元素是去重的
public static final int DISTINCT   = 0x00000001;
// 表明遍歷的順序是排好序的,再此特征值下getComparator將會返回相關聯的比較器或者null(自然排序),如果包含了此特征值,那么分割迭代器必然是ORDERED的
public static final int SORTED     = 0x00000004;
// 表明在遍歷和分割之前 estimateSize 的返回值是一個有限的值,並且在沒有源結構修改的情況下(增加、刪除等),返回值將是遍歷元素個數的准確值 這里需要看下 estimateSize 方法介紹
public static final int SIZED      = 0x00000040;
// 表明元素是非空的
public static final int NONNULL    = 0x00000100;
// 表示元素源不能進行結構修改的特征值;也就是說,無法添加,替換或刪除元素,因此在遍歷期間不會發生此類更改。不報告{IMMUTABLE}或{CONCURRENT}的Spliterator應該有關於遍歷期間檢測到的結構干擾的文檔化策略(例如拋出{@link ConcurrentModificationException})。
public static final int IMMUTABLE  = 0x00000400;
//表示可以在沒有外部同步的情況下由多個線程安全地同時修改元素源(允許添加,替換和/或刪除)的特征值。如果是這樣,Spliterator應該有一個關於遍歷期間修改影響的書面政策。頂層Spliterator不應該同時返回{CONCURRENT}和{SIZED},因為如果已知,有限大小可能會在遍歷期間同時修改源時發生更改。這樣的Spliterator是不一致的,並且不能保證使用該Spliterator進行任何計算。如果子拆分大小已知,則子拆分器可以報告{@code SIZED},並且在遍歷時不反映對源的添加或刪除。大多數並發集合維護一致性策略,保證Spliterator構造點上存在的元素的准確性,但可能不反映后續的添加或刪除。
public static final int CONCURRENT = 0x00001000;
// trySplit 返回的子分割迭代器都會是SIZED和SUBSIZED的。 分割成子,並且子的部分是固定大小的
public static final int SUBSIZED   = 0x00004000;

 

default Comparator getComparator() 對sorted的流,給出比較器。

 例子:

 

//具體實現可以去參考ArrayList的內部類ArrayListSpliterator
class ArrayListSpliterator<E> implements Spliterator<E>{ private final ArrayList<E> list; //當前迭代器所在位置 private int index; //容器總大小 private int fence; public ArrayListSpliterator(ArrayList<E> list, int index, int fence) { this.list = list; this.index = index; this.fence = fence; } //遍歷list片段中的所有元素,並執行action @Override public void forEachRemaining(Consumer<? super E> action) { for(int i = index;i < fence;i++){ action.accept(list.get(i)); } } @Override public boolean tryAdvance(@NotNull Consumer<? super E> action) { if(index < fence){ action.accept(list.get(index)); return true; } return false; } //不同線程可以獲取到不同的list片段,返回一個新的Spliterator對象 @Override public Spliterator<E> trySplit() { int current = index,end = fence,mid = ((current + end) % 2 == 0 ? (current + end) : (current + end) + 1) >>> 1; return (current >= mid) ? null : new ArrayListSpliterator<E>(list,current,index = mid); } //返回允許的最大線程數 @Override public long estimateSize() { return list.size() - index; } //返回特征值,但是我這里沒有太搞懂 @Override public int characteristics() { return 0; } } //包含spliterator的線程 class MyThread extends Thread{ private static volatile Spliterator<String> spliterator; public MyThread() { super(); } public MyThread(ArrayListSpliterator spliterator) { super(); this.spliterator = spliterator; } @Override public void run() { Spliterator split = spliterator.trySplit(); if(split != null){ split.forEachRemaining(res->{ System.out.println(res); }); } } } class Main{ //因為當list的元素個數不同時,遍歷需要的最少線程數也不同 public static void main(String[] args) throws IllegalAccessException { ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14)); ArrayListSpliterator arrayListSpliterator = new ArrayListSpliterator(list,0,list.size()); for(int i = 0;i < 4;i++){ Thread myThread = new MyThread(arrayListSpliterator); myThread.start(); } } }

  

引自:JAVA8 stream 中Spliterator的使用(一) | 並發編程網 – ifeve.com

引自:(8條消息) JAVA8學習10-spliterator 接口分析_z_yemu的博客-CSDN博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM