原文鏈接:https://www.baeldung.com/java-8-parallel-streams-custom-threadpool
1. 概述
Java 8引入了流的概念去對數據進行復雜的操作,而且使用並行流(Parallel Steams)支持併發,大大加快了運行效率。
在這篇小短文中,我們會看一下Stream API的一個最大的限制,並且我們會展示如何讓parallel stream使用我們自定義的線程池。
2. Parallel Stream
我們先來看一個簡單的例子,這個例子中,我們對集合類型使用parallelStream
方法,這將會返回一個並行流。
@Test
public void givenList_whenCallingParallelStream_shouldBeParallelStream(){
List<Long> aList = new ArrayList<>();
Stream<Long> parallelStream = aList.parallelStream();
assertTrue(parallelStream.isParallel());
}
默認情況下,Stream使用的是ForkJoinPool.commonPool()
,這是一個公用的線程池,被整個程序所使用。
3. 自定義線程池
實際上,在使用stream時,我們可以使用自定義的線程池。
下面這個例子,我們讓parallel stream使用自定義的線程池去計算閉區間1到1,000,000的和。
@Test
public void giveRangeOfLongs_whenSummedInParallel_shouldBeEqualToExpectedTotal()
throws InterruptedException, ExecutionException {
long firstNum = 1;
long lastNum = 1_000_000;
List<Long> aList = LongStream.rangeClosed(firstNum, lastNum).boxed()
.collect(Collectors.toList());
ForkJoinPool customThreadPool = new ForkJoinPool(4);
long actualTotal = customThreadPool.submit(
() -> aList.parallelStream().reduce(0L, Long::sum)).get();
assertEquals((lastNum + firstNum) * lastNum / 2, actualTotal);
}
我們使用ForkJoinPool
的構造函數去創建一個並行度爲4的線程池。需要做一些實驗去決定多大的並行度是最佳的,但簡單來說,選擇自己電腦的CPU的核心數量就可以了。
接下來,我們處理並行流的數據,調用reduce
進行加和。
這個例子可能沒有完全闡釋使用自定義線程池的好處。但是,在一些處理需要長時間運行的任務(例如,處理來自網絡流的數據)或者其他部分也在使用common pool時,我們不想讓common pool有更多的計算負載。這時候使用自定義的線程池的好處會非常明顯。
4. 結論
我們簡要的說明了如何使用自定義的線程池運行parallel Stream。在合適的環境,使用了合適的並行度(parallelism level),性能將會有所提高。
文章中完整的代碼可以在Github找到。