天天看點

解析Stream foreach源碼

摘要:串行流比較簡單,對于parallelStream,站在它背後的是ForkJoin架構。

本文分享自華為雲社群《​​深入了解Stream之foreach源碼解析​​》,作者:李哥技術 。

前言

Stream中的操作可以分為兩大類:中間操作與結束操作。

今天要說的foreach是屬于結束操作。

Stream流操作從并發上來分類,又可以分為并行流和串行流,今天就來刨根問底的看看吧。

foreach串行流

解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼

foreach并行流

解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼

從目前來看,parallelStream(并行流)與stream(串行流)的差別僅僅是一個變量而已。别着急,讓我們繼續往下看。

解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼

記住這裡的ordered是false,因為是并行流,不可能是有序周遊。continue。

解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼

我們來簡單分析一下ForEachTask類,它繼承于CountedCompleter。

static final class ForEachTask<S, T> extends CountedCompleter<Void> {
}      
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼
解析Stream foreach源碼

最後這裡使用ForkJoin架構,利用分治法的思想,将一個大任務拆分很多個小任務去執行,最後一一彙總到大任務。

我們一路過五關斬六将,終于将它給挖穿了。不容易啊。

總結

我們簡單回顧總結一下:

對于串行流:

1. 先得到ReferencePipeline.Head的Stream實作類,内部有一個拆分器,值是一個ArrayListSpliterator對象;

2. 對于并行流,目前線程直接調用ArrayListSpliterator對象的forEachRemaining方法。

對于并行流:

1. 先得到ReferencePipeline.Head的Stream實作類,内部有一個拆分器,值是一個ArrayListSpliterator對象;

2. 疊代的時候調用父類的forEach方法;

3. 建構一個ForEachTask,目前線程繼續執行invoke方法;

4. 最終執行java.util.stream.ForEachOps.ForEachTask#compute方法,使用ForkJoin架構,利用commomPool、ForkJoin架構分治法的思想,使用拆分器将任務拆分成不同子任務執行;

5. 對于每一個子任務都會拆分到不能再拆分為止,然後調用java.util.stream.AbstractPipeline#copyInto方法,在内部會調用不可再拆分的拆分器的forEachRemaining方法,最終調用回調使用者方法action.accept(e);

串行流比較簡單,對于parallelStream,站在它背後的男人是ForkJoin架構。

繼續閱讀