提交訂單效能優化系列之006-普通的Thread多執行緒改為Java8的parallelStream併發流
概括總結
Java8的parallelStream
併發流能達到跟多執行緒類似的效果,但它也不是什麼善茬,為了得到跟上一版本的多執行緒類似的效果,一改再改,雖然最後改出來了,但是還是存在理解不了的地方。
006版本更新說明
- 上一版本中寫了多個測試類,每個類針對一個執行緒數量。寫這一版的時候覺得上一版本有點太傻了,於是花了點時間想了想辦法,發現確實可以在一個類中完成。也證明了上一版的寫法確實是傻。
- 把多執行緒(即
new Thread().start()
)的方式改為了Java8的parallelStream
。
怎樣得到一個parallelStream
理論上,你需要先有一個List<?>
,任意型別的List都行,然後呼叫它的.parallelStream()
方法就可以了。
對我這個例子來說,元素的型別不重要,因此選擇了Integer
型別,核心程式碼如下:
AtomicInteger atomicInteger = new AtomicInteger(0);
return Arrays.asList(new Integer[size]).parallelStream().map(i -> atomicInteger.incrementAndGet());
值得注意的是,第一行用的是AtomicInteger
而不是Integer
,因為Integer
會存在併發問題。
第二行的意思是:新建一個大小為size
的陣列,把陣列轉成List
,再把List轉成parallelStream
,再把列表中的元素初始化成遞增的整數,最後返回。
為什麼說parallelStream不是什麼善茬
簡單來說,我認為原因是:因為它的預設值適用的場景是CPU密集型
的,而一般的Web專案是IO密集型
的(一般的Web專案都是需要跟資料庫打交道的,針對資料庫的操作主要就都是IO
,而對CPU的消耗並不高)。
當不能使用預設值的時候,就需要開發人員額外去了解parallelStream
的用法,而這些資料還不是特別好找。比如說:parallelStream
預設的併發執行緒數是多少?怎麼修改預設的執行緒數?
我最終找到了這篇問答:Custom thread pool in Java 8 parallel stream,供參考。
問題1: 在Java程式碼中,怎樣獲取可用的CPU處理器的數量?程式碼如下:(在我的機器上結果是:8)
Runtime.getRuntime().availableProcessors()
問題2: parallelStream預設的併發執行緒數是多少?程式碼如下:(在我的機器上結果是:7)
ForkJoinPool.getCommonPoolParallelism()
問題3: 為什麼parallelStream預設的併發執行緒數要比CPU處理器的數量少1個?因為最優的策略是每個CPU處理器分配一個執行緒,然而主執行緒也算一個執行緒,所以要佔一個名額。
問題4: 那如果電腦比較差,就只有1個CPU要怎麼辦?那就不管了,預設的併發執行緒數就是1,總不能為零吧。
問題5: 預設的併發執行緒數太少了,要怎麼修改?如程式碼如下:(改成了20)
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");
問題6: 預設的併發執行緒數可以反覆修改嗎?不能。因為java.util.concurrent.ForkJoinPool.common.parallelism
是final
型別的,整個JVM中只允許設定一次。
執行以下程式碼:
int[] threadCountArr = {32, 48, 72};
for (int threadCount : threadCountArr) {
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "" + threadCount);
System.out.println("ForkJoinPool.getCommonPoolParallelism() : " + ForkJoinPool.getCommonPoolParallelism());
}
列印結果如下:
ForkJoinPool.getCommonPoolParallelism() : 32
ForkJoinPool.getCommonPoolParallelism() : 32
ForkJoinPool.getCommonPoolParallelism() : 32
問題7: 既然預設的併發執行緒數不能反覆修改,那怎麼進行不同執行緒數量的併發測試呢?答案是:引入ForkJoinPool
。用法如下:
new ForkJoinPool(threadCount).submit(() -> {
parallelStream.forEach(i -> {
// 這裡省略提交訂單的程式碼
});
}).get();
問題8: java.util.concurrent.ForkJoinPool.common.parallelism
與new ForkJoinPool(threadCount)
之間有什麼關係?答案是:不知道。
這個答案很讓人失望,但是我確實沒有查出來。我這邊測試的結果是:
-
如果在
new ForkJoinPool(threadCount)
之前沒有設定java.util.concurrent.ForkJoinPool.common.parallelism
的值,那麼new ForkJoinPool(threadCount)
的作用就不明顯,即就是說,改變threadCount
的值對效能沒有多大影響。 -
如果在之前設定了
java.util.concurrent.ForkJoinPool.common.parallelism
的值,但是設定得比較小(比如32),則後續的new ForkJoinPool(threadCount)
的作用也不明顯。 -
只有先把
java.util.concurrent.ForkJoinPool.common.parallelism
的值設定得比較大(比如10000),後續的new ForkJoinPool(threadCount)
中threadCount
改變之後,才對效能有明顯的影響。
問題9: 如果按問題8中的來修改,把java.util.concurrent.ForkJoinPool.common.parallelism
的值設定得比較大(比如10000),就意味不再適用於CPU密集型
的操作了,那應該怎麼辦呢?答案是:每次都用new ForkJoinPool(threadCount)
,整體放棄使用預設的parallelStream
。(那多麻煩啊)
你看,隨隨便便就有這麼多問題,頓時就不想用了,是不是。
“併發執行緒數量”與“每秒能提交的訂單數量”之間的關係
這次測試的結果與上次測試的結果對比圖如下:(紅色為上一版本使用Thread測試的結果,黑色為這一版本使用parallelStream測試的結果)
可以看到差別並不大。
【備註】:不同的機器上的測試結果會不一樣,以上測試結果僅供參考。
原始碼
006版本的github原始碼在這裡,如果不知道怎樣執行專案,請參考這裡
(轉載本站文章請註明出處二胡1999 的個人技術部落格www.erhu1999.com ,請勿用於任何商業用途)
相關文章
- 多執行緒系列(二)之Thread類執行緒thread
- mysql併發執行緒控制之innodb_thread_concurrency的改進MySql執行緒thread
- Java併發 之 執行緒池系列 (1) 讓多執行緒不再坑爹的執行緒池Java執行緒
- MySQL多執行緒併發調優MySql執行緒
- 併發與多執行緒之執行緒安全篇執行緒
- mysql併發執行緒控制之thread pool和優先佇列MySql執行緒thread佇列
- Java多執行緒/併發07、Thread.Join()讓呼叫執行緒等待子執行緒Java執行緒thread
- java多執行緒之Thread類Java執行緒thread
- python 多執行緒之threadPython執行緒thread
- 多執行緒系列之 執行緒安全執行緒
- Python多執行緒併發的簡單測試Python執行緒
- parallelStream中的執行緒安全問題Parallel執行緒
- java多執行緒系列之執行緒池Java執行緒
- C++11併發程式設計:多執行緒std::threadC++程式設計執行緒thread
- JAVA多執行緒併發Java執行緒
- 多執行緒併發篇——如何停止執行緒執行緒
- 多執行緒程式設計,處理多執行緒的併發問題(執行緒池)執行緒程式設計
- javascript執行緒及與執行緒有關的效能優化JavaScript執行緒優化
- Java多執行緒與併發之ThreadLocalJava執行緒thread
- Java學習之併發多執行緒理解Java執行緒
- 24. 一個普通main方法的執行,是單執行緒模式還是多執行緒模式?為什麼?AI執行緒模式
- Java 執行緒與同步的效能優化Java執行緒優化
- 常用高併發網路執行緒模型效能優化實現-體驗百萬級高併發執行緒模型設計執行緒模型優化
- Java併發系列 — 執行緒池Java執行緒
- 多執行緒與高併發(一)多執行緒入門執行緒
- Java多執行緒之Thread原始碼分析Java執行緒thread原始碼
- 多執行緒與高併發(二)執行緒安全執行緒
- java 多執行緒 併發 面試Java執行緒面試
- MySQL併發複製系列二:多執行緒複製MySql執行緒
- 多執行緒系列(十五) -常用併發工具類詳解執行緒
- 多執行緒系列(十六) -常用併發原子類詳解執行緒
- 求教:jboss對多執行緒併發的支援執行緒
- JUC之Exchanger-多執行緒與高併發執行緒
- iOS多執行緒之併發程式設計-4iOS執行緒程式設計
- Java 併發和多執行緒(一) Java併發性和多執行緒介紹[轉]Java執行緒
- java多執行緒系列之synchronousQueueJava執行緒
- Java高併發與多執行緒(二)-----執行緒的實現方式Java執行緒
- mysql併發執行緒控制之控制thread_running數量MySql執行緒thread