parallelStream 一定更快嗎? 大家都知道 Stream 分為順序流和並行流: stream(順序流) parallelStream(並行流) 它們最大的區別就是 parallelStream 支持並行化處理,所以效率較 stream(順序流)肯定是要更快的。這篇不會介紹 Stream ...
parallelStream 一定更快嗎?
大家都知道 Stream 分為順序流和並行流:
- stream(順序流)
- parallelStream(並行流)
它們最大的區別就是 parallelStream 支持並行化處理,所以效率較 stream(順序流)肯定是要更快的。這篇不會介紹 Stream 基礎,Stream 系列我之前寫過一個專題了,不懂的關註公眾號Java技術棧,然後在公眾號 Java 教程菜單中閱讀。
然而你確定 parallelStream 一定要更快嗎?
棧長寫了一段排序的示例,分別用 stream 和 parallelStream,對 100 ~ 10000000 條數據的集合進行排序,來看下執行效率究竟如何!
順序流排序:
/**
* 順序流排序
* @author: 棧長
* @from: 公眾號Java技術棧
*/
private static void streamSort() {
long start = System.currentTimeMillis();
List<SortTest.User> list = new ArrayList<>(LIST);
list.stream().sorted(SortTest.User::compareAge).collect(Collectors.toList());
System.out.println("\nList size: " + list.size() + " Stream.sorted: " + (System.currentTimeMillis() - start));
}
並行流排序:
/**
* 並行流排序
* @author: 棧長
* @from: 公眾號Java技術棧
*/
private static void parallelStreamSort() {
long start = System.currentTimeMillis();
List<SortTest.User> list = new ArrayList<>(LIST);
list.parallelStream().sorted(SortTest.User::compareAge).collect(Collectors.toList());
System.out.println("List size: " + list.size() + " ParallelStream.sorted: " + (System.currentTimeMillis() - start));
}
本文所有完整示例源代碼已經上傳:
執行結果如下:
List size: 10000000 Stream.sorted: 202
List size: 10000000 ParallelStream.sorted: 402List size: 1000000 Stream.sorted: 53
List size: 1000000 ParallelStream.sorted: 15List size: 100000 Stream.sorted: 1
List size: 100000 ParallelStream.sorted: 2List size: 10000 Stream.sorted: 0
List size: 10000 ParallelStream.sorted: 1List size: 1000 Stream.sorted: 0
List size: 1000 ParallelStream.sorted: 1List size: 100 Stream.sorted: 0
List size: 100 ParallelStream.sorted: 0
在 100000 以下是沒什麼區別的;
在 1000000 左右 ParallelStream 雖然領先 Stream,但也不是絕對每次都領先,經過不斷測試,這個數據量區間的測試兩者會互相領先;
在 10000000 左右就很穩定了,ParallelStream 幾乎比 Stream 慢了 2 倍!
現在你可能會有疑問了,為什麼會這樣?
棧長起初也有疑問,並行流(ParallelStream)怎麼會比順序流(Stream)還要慢。。
其實我後面想想也就明白了,並行流(ParallelStream)的背後其實是 Java7 開始支持的 Fork/Join,即把一個大任務拆分成 N 個小任務,然後最終合併各個子任務的結果,所以對於子任務線程的拆分、創建、結果合併等操作都需要不少的開銷,特別是線程的創建。
所以這種不耗時的簡單排序操作事實上是不適用於並行流(ParallelStream)的,它所帶來的線程創建的損耗可能還會比順序流(Stream)還要更慢。
最新 Java 8+ 面試題也都整理好了,點擊Java面試庫小程式線上刷題。
什麼時候用 ParallelStream?
既然使用 Fork/Join 是會有損耗的,那對於單條數據的處理的時間最好是理論上要超過用並行流(ParallelStream)本身的損耗,這種情況下就比較合適。
也就是說,如果對於流中的每條數據的處理比較費時間,並且沒有順序要求,這種場景下用並行流(ParallelStream)會更快,更合適。
來看下麵這個示例:
順序流數據處理:
/**
* 順序流數據處理
* @author: 棧長
* @from: 公眾號Java技術棧
*/
private static void streamProcess() {
long start = System.currentTimeMillis();
List<SortTest.User> list = new ArrayList<>(LIST);
list.stream().map(StreamSpeedTest::process).collect(Collectors.toList());
System.out.println("\nList size: " + list.size() + " Stream process: " + (System.currentTimeMillis() - start));
}
並行流數據處理:
/**
* 並行流數據處理
* @author: 棧長
* @from: 公眾號Java技術棧
*/
private static void parallelStreamProcess() {
long start = System.currentTimeMillis();
List<SortTest.User> list = new ArrayList<>(LIST);
list.parallelStream().map(StreamSpeedTest::process).collect(Collectors.toList());
System.out.println("List size: " + list.size() + " ParallelStream process: " + (System.currentTimeMillis() - start));
}
數據處理:
/**
* 數據處理
* @author: 棧長
* @from: 公眾號Java技術棧
*/
private static SortTest.User process(SortTest.User user) {
try {
user.setName(user.getName() + ": process");
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return user;
}
註意: 這裡加了個休眠 5 毫秒,為了體現真實的處理數據耗時。
本文所有完整示例源代碼已經上傳:
並行流排序:
List size: 1000 Stream process: 5750
List size: 1000 ParallelStream process: 745List size: 100 Stream process: 566
List size: 100 ParallelStream process: 77
結果很明顯了,不管測試多少次,並行流(ParallelStream)的處理速度都要比順序流(Stream)要快幾倍!!我這裡只測試了 100 和 1000 條數據,因為 10000 條以上的數據用順序流(Stream)可能要等非常久。
而且我程式中的處理邏輯只休眠了 5 毫秒,如果實際處理單條數據的耗時要比這個更長,那並行流(ParallelStream)的處理效率還會更明顯。
總結
稍微總結下:
- stream: 適用於避免線程安全問題、要求順序執行、數據處理簡單不耗時的任務;
- parallelStream: 適用於不存線上程安全問題、不需要順序性執行、數據處理比較耗時的任務;
所以,你學廢了嗎?趕緊發給身邊的同事看看吧,別再亂用 parallelStream 了!用的不好,存線上程安全問題不說,效率上可能還會適得其反。
大家如果對 Java 8 新增的知識點(Lambda、Stream、函數式介面等)還不會用的可以關註公眾號:Java技術棧,在 Java 教程菜單中閱讀,Java 8+ 系列教程我都寫了一堆了。
本文所有完整示例源代碼已經上傳:
歡迎 Star 學習,後面 Java 示例都會在這上面提供!
好了,今天的分享就到這裡了,後面棧長會分享更多好玩的 Java 技術和最新的技術資訊,關註公眾號Java技術棧第一時間推送,我也將主流 Java 面試題和參考答案都整理好了,在公眾號後臺回覆關鍵字 "面試" 進行刷題。
最後,覺得我的文章對你用收穫的話,動動小手,給個在看、轉發,原創不易,棧長需要你的鼓勵。
版權聲明: 本文系公眾號 "Java技術棧" 原創,轉載、引用本文內容請註明出處,抄襲、洗稿一律投訴侵權,後果自負,並保留追究其法律責任的權利。
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
覺得不錯,別忘了隨手點贊+轉發哦!