1. 一個 SpringBoot 項目能同時處理多少請求?tomcat容器,
200 次。
2. 怎么來的?
而點擊這些線程,查看其堆棧消息,可以看到 Tomcat、threads、ThreadPoolExecutor 等關鍵字
基于“短時間內有 200 個請求被立馬處理的”這個現象,結合你背的滾瓜爛熟的、非常扎實的線程池知識,你先大膽的猜一個:Tomcat 默認核心線程數是 200。
從這個調用棧中,由于我們要找的是 Tomcat 線程池相關的源碼,所以第一次出現相關關鍵字的地方就是這一行:
org.apache.Tomcat.util.threads.ThreadPoolExecutor.Worker#run
corePoolSize,核心線程數,值為 10。
maximumPoolSize,最大線程數,值為 200。
而且基于 maximumPoolSize 這個參數,你往前翻代碼,會發現這個默認值就是 200:
隊列長度,值為 Integer.MAX_VALUE。
這個方法里面,標號為 ① 的地方,就是判斷當前工作線程數是否小于核心線程數,小于則直接調用 addWorker 方法,創建線程。
標號為 ② 的地方主要是調用了 offer 方法,看看隊列里面是否還能繼續添加任務。
如果不能繼續添加,說明隊列滿了,則來到標號為 ③ 的地方,看看是否能執行 addWorker 方法,創建非核心線程,即啟用最大線程數。
把這個邏輯捋順之后,接下來我們應該去看哪部分的代碼,就很清晰了。
主要就是去看 workQueue.offer(command) 這個邏輯。
如果返回 true 則表示加入到隊列,返回 false 則表示啟用最大線程數嘛。
這個 workQueue 是 TaskQueue,看起來一點也不眼熟:
當然不眼熟了,因為這個是 Tomcat 自己基于 LinkedBlockingQueue 搞的一個隊列。
重點:題的答案就藏在 TaskQueue 的 offer 方法里面。
parent 就是 Tomcat 線程池,通過其 set 方法可以知道,是在線程池完成初始化之后,進行了賦值。
也就是說,你可以理解為,在 Tomcat 的場景下,parent 不會為空。
標號為 ② 的地方,調用了 getPoolSizeNoLock 方法:
就表明當前線程池的線程數已經是配置的最大線程數了,那就調用 offer 方法,把當前請求放到到隊列里面去。
標號為 ③ 的地方,是判斷已經提交到線程池里面待執行或者正在執行的任務個數,是否比當前線程池的線程數還少。
如果是,則說明當前線程池有空閑線程可以執行任務,則把任務放到隊列里面去,就會被空閑線程給取走執行。
然后,關鍵的來了,標號為 ④ 的地方。
重點:如果當前線程池的線程數比線程池配置的最大線程數還少,則返回 false。
前面說了,offer 方法返回 false,會出現什么情況?
是不是直接開始到上圖中標號為 ③ 的地方,去嘗試添加非核心線程了?
也就是啟用最大線程數這個配置了。
3. JDK線程池和Tomcat線程池原理不一樣
JDK 的線程池,是先使用核心線程數配置,接著使用隊列長度,最后再使用最大線程配置。
Tomcat 的線程池,就是先使用核心線程數配置,再使用最大線程配置,最后才使用隊列長度。
https://mp.weixin.qq.com/s/PXC4pFE_ZpydBAzCJZmiqQ