成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

原生線程池這么強大,Tomcat 為何還需擴展線程池?

開發 架構
Tomcat/Jetty 是目前比較流行的 Web 容器,兩者接受請求之后都會轉交給線程池處理,這樣可以有效提高處理的能力與并發度。

[[286996]]

前言

Tomcat/Jetty 是目前比較流行的 Web 容器,兩者接受請求之后都會轉交給線程池處理,這樣可以有效提高處理的能力與并發度。JDK 提高完整線程池實現,但是 Tomcat/Jetty 都沒有直接使用。Jetty 采用自研方案,內部實現 QueuedThreadPool 線程池組件,而 Tomcat 采用擴展方案,踩在 JDK 線程池的肩膀上,擴展 JDK 原生線程池。

JDK 原生線程池可以說功能比較完善,使用也比較簡單,那為何 Tomcat/Jetty 卻不選擇這個方案,反而自己去動手實現那?

JDK 線程池

通常我們可以將執行的任務分為兩類:

  • cpu 密集型任務
  • io 密集型任務

cpu 密集型任務,需要線程長時間進行的復雜的運算,這種類型的任務需要少創建線程,過多的線程將會頻繁引起上文切換,降低任務處理處理速度。

而 io 密集型任務,由于線程并不是一直在運行,可能大部分時間在等待 IO 讀取/寫入數據,增加線程數量可以提高并發度,盡可能多處理任務。

JDK 原生線程池工作流程如下:

 

線程池執行流程圖

“詳情可以查看 一文教你安全的關閉線程池, 上圖假設使用 LinkedBlockingQueue。

“靈魂拷問:上述流程是否記錯過?在很長一段時間內,我都認為線程數量到達最大線程數,才放入隊列中。 ̄□ ̄||

上圖中可以發現只要線程池線程數量大于核心線程數,就會先將任務加入到任務隊列中,只有任務隊列加入失敗,才會再新建線程。也就是說原生線程池隊列未滿之前,最多只有核心線程數量線程。

這種策略顯然比較適合處理 cpu 密集型任務,但是對于 io 密集型任務,如數據庫查詢,rpc 請求調用等,就不是很友好了。

由于 Tomcat/Jetty 需要處理大量客戶端請求任務,如果采用原生線程池,一旦接受請求數量大于線程池核心線程數,這些請求就會被放入到隊列中,等待核心線程處理。這樣做顯然降低這些請求總體處理速度,所以兩者都沒采用 JDK 原生線程池。

解決上面的辦法可以像 Jetty 自己實現線程池組件,這樣就可以更加適配內部邏輯,不過開發難度比較大,另一種就像 Tomcat 一樣,擴展原生 JDK 線程池,實現比較簡單。

下面主要以 Tomcat 擴展線程池,講講其實現原理。

擴展線程池

首先我們從 JDK 線程池源碼出發,查看如何這個基礎上擴展。

 

可以看到線程池流程主要分為三步,第二步根據 queue#offer 方法返回結果,判斷是否需要新建線程。

JDK 原生隊列類型 LinkedBlockingQueue, SynchronousQueue,兩者實現邏輯不盡相同。

LinkedBlockingQueue

offer 方法內部將會根據隊列是否已滿作為判斷條件。若隊列已滿,返回 false,若隊列未滿,則將任務加入隊列中,且返回 true。

SynchronousQueue

這個隊列比較特殊,內部不會儲存任何數據。若有線程將任務放入其中將會被阻塞,直到其他線程將任務取出。反之,若無其他線程將任務放入其中,該隊列取任務的方法也將會被阻塞,直到其他線程將任務放入。

對于 offer 方法來說,若有其他線程正在被取方法阻塞,該方法將會返回 true。反之,offer 方法將會返回 false。

所以若想實現適合 io 密集型任務線程池,即優先新建線程處理任務,關鍵在于 queue#offer 方法。可以重寫該方法內部邏輯,只要當前線程池數量小于最大線程數,該方法返回false,線程池新建線程處理。

當然上述實現邏輯比較糙,下面我們就從 Tomcat 源碼查看其實現邏輯。

Tomcat 擴展線程池

Tomcat 擴展線程池直接繼承 JDK 線程池 java.util.concurrent.ThreadPoolExecutor,重寫部分方法的邏輯。另外還實現了 TaskQueue,直接繼承 LinkedBlockingQueue,重寫 offer 方法。

首先查看 Tomcat 線程池的使用方法。

 

可以看到 Tomcat 線程池使用方法與普通的線程池差不太多。

接著我們查看一下 Tomcat 線程池核心方法 execute 的邏輯。

 

execute 方法邏輯比較簡單,任務核心還是交給 Java 原生線程池處理。這里主要增加一個重試策略,如果原生線程池執行拒絕策略的情況,拋出 RejectedExecutionException 異常。這里將會捕獲,然后重新再次嘗試將任務加入到 TaskQueue ,盡最大可能執行任務。

這里需要注意 submittedCount 變量。這是 Tomcat 線程池內部一個重要的參數,它是一個 AtomicInteger 變量,將會實時統計已經提交到線程池中,但還沒有執行結束的任務。也就是說 submittedCount 等于線程池隊列中的任務數加上線程池工作線程正在執行的任務。TaskQueue#offer 將會使用該參數實現相應的邏輯。

接著我們主要查看 TaskQueue#offer 方法邏輯。

 

核心邏輯在于第三步,這里如果 submittedCount 小于當前線程池線程數量,將會返回false。上面我們講到 offer 方法返回 false,線程池將會直接創建新線程。

Dubbo 2.6.X 版本增加 EagerThreadPool,其實現原理與 Tomcat 線程池差不多,感興趣的小伙伴可以自行翻閱。

折衷方法

上述擴展方法雖然看起不是很難,但是自己實現代價可能就比較大。若不想擴展線程池運行 io 密集型任務,可以采用下面這種折衷方法。

new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(100));

不過使用這種方式將會使 keepAliveTime 失效,線程一旦被創建,將會一直存在,比較浪費系統資源。

總結

JDK 實現線程池功能比較完善,但是比較適合運行 CPU 密集型任務,不適合 IO 密集型的任務。對于 IO 密集型任務可以間接通過設置線程池參數方式做到。

責任編輯:武曉燕 來源: Java極客技術
相關推薦

2021-08-20 08:22:12

Tomcat原生線程池

2023-05-19 08:01:24

Key消費場景

2024-07-15 08:20:24

2023-10-13 08:20:02

Spring線程池id

2012-05-15 02:18:31

Java線程池

2020-12-10 08:24:40

線程池線程方法

2018-04-27 10:35:08

Tomcat連接數線程池

2023-06-07 13:49:00

多線程編程C#

2025-01-09 11:24:59

線程池美團動態配置中心

2017-01-10 13:39:57

Python線程池進程池

2012-02-29 13:26:20

Java

2024-11-21 07:00:00

線程池Java開發

2024-12-13 08:21:04

2020-09-04 10:29:47

Java線程池并發

2013-05-28 13:57:12

MariaDB

2011-06-22 15:50:45

QT 線程

2020-03-05 15:34:16

線程池C語言局域網

2023-11-22 08:37:40

Java線程池

2013-05-23 15:59:00

線程池

2013-06-08 13:07:23

Java線程池調度器
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: www.youjizz.com日韩 | 国产在线网站 | 国产视频二区 | 日韩欧美在线观看视频 | 欧美一区二不卡视频 | 91在线看 | 在线免费观看成年人视频 | 一级免费看 | 欧美日韩精品久久久免费观看 | 日本久草 | 欧美黄色网 | 涩涩99| 日韩精品一区二区不卡 | 国内精品视频免费观看 | 日韩精品一区在线观看 | 成人性视频在线播放 | 国产亚洲精品久久情网 | 国产精品一区二区三区四区 | 国内av在线| 久久99精品国产 | 国产成人免费网站 | 在线看亚洲 | 精品日韩一区 | 日本午夜免费福利视频 | 国产精品一区在线观看 | 特黄特黄a级毛片免费专区 av网站免费在线观看 | www.99热.com | 欧美日韩在线观看一区 | 日韩精品视频在线免费观看 | 国产乱码久久久久久一区二区 | 精品人伦一区二区三区蜜桃网站 | 亚洲一区二区精品 | 日韩视频一区二区 | 久久99蜜桃综合影院免费观看 | 91久久综合亚洲鲁鲁五月天 | a视频在线观看 | 国产午夜精品久久久 | 日韩国产中文字幕 | 视频一区二区在线观看 | 国产一区二区三区在线 | 欧美日韩中文字幕在线 |