定製Java 8的Parallel Streams使用的線程池

原文鏈接: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找到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章