2 回答

TA貢獻1790條經(jīng)驗 獲得超9個贊
這是一個有趣的。
您列出的代碼失敗的原因是因為將元素從工作隊列傳輸?shù)焦ぷ骶€程所花費的時間比主線程將項目放入隊列所花費的時間慢。
流程是這樣的:
if(there are active threads and is there availability on the queue){
submit to the work queue for the worker threads to pick up // 1
} else {
if(max pool size is not met){
create a new thread with this task being its first task // 2
} else {
reject // 3
}
}
您看到的是代碼命中// 3.
首次提交任務時,線程數(shù)將小于最大池大小。第一輪提交的任務將到達// 2。
第一次迭代后,活動線程的數(shù)量將是最大池大小,代碼將嘗試提交到// 1.
假設主線程非常非??斓貙?3 個項目放入隊列,因此 ThreadPool 中的 4 個線程無法足夠快地取出一個。如果發(fā)生這種情況,我們將傳遞第一個 if 語句(因為隊列中沒有可用性)并轉到 else。由于已經(jīng)滿足最大池大小,因此除了reject.
這可以通過檢查ThreadPoolExecutor Javadocs進一步解釋。
如果請求無法排隊,則會創(chuàng)建一個新線程,除非這會超過 maximumPoolSize,在這種情況下,任務將被拒絕。
然后
直接切換通常需要無限的 maximumPoolSizes 以避免拒絕新提交的任務。當命令的平均到達速度繼續(xù)快于它們的處理速度時,這反過來又承認了無限線程增長的可能性。
要解決您的問題,您有兩個合理的選擇:
使用同步隊列。提供給 SynchronousQueue 的線程將無限期地等待,直到另一個線程獲取該項目(如果它知道另一個線程正在等待接收它)。您定義的固定隊列大小將導致主線程在放置不成功時返回(不阻塞)(即,另一個線程不會立即將其取消)。要使用 Spring 使用 SynchronousQueue,請將隊列容量設置為零。
setQueueCapacity(0)
. 也來自 Javadocs工作隊列的一個很好的默認選擇是 SynchronousQueue,它將任務交給線程而不用其他方式持有它們。
將隊列大小設置為大于或等于您希望提交的并發(fā)任務數(shù)。隊列的大小一般不會達到那個大小,但它會在未來保護你。

TA貢獻1829條經(jīng)驗 獲得超9個贊
我建議通過添加 1 個輸出任務執(zhí)行程序的記錄器行來對此進行測試,然后對不同的 16 次調用和 45 次請求進行計數(shù)??赡軙l(fā)生很多事情。
也許 ThreadPoolTaskExecutor 不是一個 bean,而 spring 會選擇另一個在您的應用程序中配置的 bean。
也許應用程序的其他部分也在使用異步調用
永遠循環(huán)的代碼中可能存在一些錯誤
ETC...
但是,如果您沒有單元測試,一個好的開始是簡單地記錄正在發(fā)生的事情并分析您的日志。
添加回答
舉報