你知道Java8有哪些提升效率的利器嗎?

# 寫在前面的話

在前面我們已經看過了一些流的處理,那麼Lambda除了在寫法上的不同,還有其它什麼作用呢?當然有,就是數據並行化處理!

它在某些場景下可以提高程序的性能。我們先看一個前面的例子,查找所有的男同學

// 流方式List newBoys = personList.stream().filter(p -> 1 == p.getSex()).collect(Collectors.toList());

現在用並行流改寫一下

// 流方式:找出所有男同學 List newBoys = personList.parallelStream().filter(p -> 1 == p.getSex()).collect(Collectors.toList());

細心的同學已經發現區別了,stream與parallelStream,是的,要用並行流parallelStream,就是這麼簡單!

# 什麼是並行

有必要嘗試解釋一下,什麼是數據並行化

Java支持多線程,可以同時開啓多個任務。引入多線程的原因在於,線程可能會阻塞,CPU會主動切分時間片,只有分配到時間片的線程才會運行。而現代的處理器,幾乎都是多核的,即多個CPU,如何才能更高效的利用硬件呢,多線程。

並行和多線程是有區別的,比如運送一堆貨物,如果只有一輛車(單線程),肯定慢,平時如果貨少,那還能應付過來 ,如果比如某寶的"雙十一",那就肯定快遞像垃圾一樣如山,怎麼辦呢?我們可以增加車輛(多線程),那麼肯定能加快運送速度。但是有一個前提,必須是多條道(多核CPU)。而在有些只有單個出口的地方,還必須排隊(併發,線程安全)

而並行的針對同一個任務的。比如還是一輛車的貨,10000件,全部放在A車上,要跑N個小時。現在取出一半放到B車上,理論上A,B2車同時跑,是不是會理快呢?嘿嘿嘿,這就是説的數據並行化,這裏不會涉及併發。而這一切,Java8的並行流都在底層幫我們實現了

# 一定會更快?

紙上得來終覺淺,絕知此事要躬行!我們來看下,前面2個代碼的分別執行時間

@Testpublic void test() {

// 數據並行化處理// 學生集合 Person kobe = new Person("kobe", 40, 1); Person jordan = new Person("jordan", 50, 1); Person mess = new Person("mess", 20, 2); List personList = Arrays.asList(kobe, jordan, mess);

long beginTime = System.currentTimeMillis();

// 原來的方式List oldBoys = new ArrayList(personList.size());for (Person p : personList) {// 性別男if (p.getSex() == 1) {oldBoys.add(p);}}long endTime = System.currentTimeMillis();log.info("原來的方式 take time:" + (endTime - beginTime));

beginTime = System.currentTimeMillis();// 流方式:找出所有男同學 List newBoys = personList.stream() .filter(p -> 1 == p.getSex()) .collect(Collectors.toList());

endTime = System.currentTimeMillis(); log.info("流方式 take time:" + (endTime - beginTime));

beginTime = System.currentTimeMillis();// 流方式:找出所有男同學 List parallelBoys = personList.parallelStream() .filter(p -> 1 == p.getSex()) .collect(Collectors.toList());

endTime = System.currentTimeMillis(); log.info("並行流方式 take time:" + (endTime - beginTime)); }

咦,是不是很奇怪,原來的for循環方式最快?多執行幾次,發現結果也是這樣的,那真是這樣嗎,我們把數據量擴大試試

我靠,還是更慢,換個方法試試

@Testpublic void test() {

// 學生集合 List personList = new ArrayList(1000000);for (int i = 0, j = 1000000; i < j; i++) {int sex = i % 2; Person p = new Person(String.valueOf(i), i, sex); personList.add(p); }

long beginTime2 = System.currentTimeMillis();// 流方式:年齡之和int parallelAges = personList.parallelStream().mapToInt(p -> p.getAge()).sum();

long endTime2 = System.currentTimeMillis(); log.info("並行流方式 take time:" + (endTime2 - beginTime2)); log.info("parallelAges:" + parallelAges);

long beginTime = System.currentTimeMillis();

// 原來的方式int totalAge = 0;for (Person p : personList) {// 年齡之和 totalAge = totalAge + p.getAge(); }long endTime = System.currentTimeMillis(); log.info("原來的方式 take time:" + (endTime - beginTime)); log.info("totalAge:" + totalAge);

看看結果,還是更慢。。。這倒很出我意外,崩潰了,

可能跟我機器有關吧。所以還是需要找地方驗證,如果哪位同學能解答一下,歡迎指教

這裏引用一下《java8函數式編程》的結論

你知道Java8有哪些提升效率的利器嗎?
# 一些條件

輸入數據的大小。

理論上輸入的數據越大,操作越複雜,並行流的效果越好。因為拆分數據處理,最後合併結果都會帶來額外的開銷。我們可以通過修改前面的例子,personList的大小來觀察

你知道Java8有哪些提升效率的利器嗎?
可以看到,數據越大,並行效果越好。當然,真實項目中的處理遠比上面複雜,而超過1000w的數據,我本地機器就OOM了

數據結構

我們通常是操作集合。一般來説,越好分割的並行速度越快。比如ArrayList,數組等支持隨機讀取的,效果較好。

HashSet,TreeSet,這類不容易公平的分解。而LinkedList,Stream.iterator等分解就比較困難的,效果是比較差的

裝箱

處理包裝類比基本類型花的時間多,肉眼可見

核的數量

當然,如果核的數量越多,獲得潛在並行提升速度的趕快。比如4核一般比雙核快,對吧

來源:https://blog.csdn.net/weigeshikebi/article/details/80030312

往期推薦

幾道被問爛的Spring Cloud面試題(附答案)~

厲害!某生鮮電商平台竟然是這樣設計監控模塊的(已開源)~

裸辭1天 vs 裸辭10天 vs 裸辭一個月

點擊閲讀原文,獲得更多精彩內容

版權聲明:本文源自 網絡, 於,由 楠木軒 整理發佈,共 3267 字。

轉載請註明: 你知道Java8有哪些提升效率的利器嗎? - 楠木軒