線程池阻塞隊列滿了該怎麼辦,線上宕機了隊列裡的請求會丟嗎

2020-12-13 Java章魚小弟

如果在線程池中使用無界阻塞隊列會發生什麼問題?要回答這個問題首先要對線程池的工作原理非常熟悉,如果忘了的可以看下這篇文章線程池的核心參數及工作原理

線程池用無界阻塞隊列會有什麼影響

有一個面試題:在遠程服務異常的情況下,使用無界阻塞隊列是否會導致內存異常飆升?這個問題的意思是遠程服務不可用會導致接口調用超時,新任務不斷提交到線程池,隊列變成得越來越大,此時會導致內存飆升起來,而且還可能會導致內存溢出OOM。通常線程池都是設置成有界隊列加一個拒絕策略。

線程池內線程調用遠程服務超時

有界隊列可以避免內存溢出,但是如果線程池的核心參數maximumPoolSize=Integer.MAX_VALUE的話,代表你可以無限制的不停地創建額外的線程出來處理任務,一臺機子有幾千甚至幾萬個線程,我們知道每個線程都有自己的線程棧,是需要佔用一定內存資源的,垃圾回收又回收不了,會導致內存資源被耗盡,系統也會崩潰掉,即使沒有崩潰也會讓機子的cpu負載特別高。所以線程池一般建議maximumPoolSize和corePoolSize設置成一樣,當工作隊列存滿了之後,交給拒絕策略去處理。

線程池自帶的四種拒絕策略

1、ThreadPoolExecutor.AbortPolicy

直接丟棄任務並拋出RejectedExecutionException異常,這是線程池默認的拒絕策略

2、ThreadPoolExecutor.DiscardPolicy

也是直接丟棄任務,但是不拋出異常

3、ThreadPoolExecutor.DiscardOldestPolicy

丟棄隊列老的任務,然後重新嘗試執行任務(重複此過程)

4、ThreadPoolExecutor.CallerRunsPolicy

由調用線程(理解成主線程)處理該任務

線程池隊列滿了,你該怎麼辦

真正的生產環境可以根據自己業務需要,選擇通過實現RejectedExecutionHandler接口來自定義拒絕策略。比如把線程池無法執行的任務信息持久化寫入資料庫去,後臺專門啟動一個線程,後續等待線程池的工作負載降低了,這個後臺線程就可以慢慢的從磁碟裡讀取之前持久化的任務重新提交到線程池。

線上機器宕機,線程池阻塞隊列中的請求怎麼辦

我們知道隊列裡任務請求如果只在內存,沒有持久化的話,機器宕機隊列中的請求肯定會丟失。那麼是不是可以在任務提交到線程池前,先把任務信息插入到資料庫加個狀態欄位:未提交,當任務提交到線程池後,再更新狀態為已提交,任務執行完之後再更新狀態為已完成。機器宕機系統重啟後,啟動一個後臺線程去讀取未提交和已提交的任務信息,重新提交到線程池,繼續執行任務。

相關焦點

  • 阻塞隊列實現生產者消費者以及同步工具類
    阻塞隊列阻塞隊列提供可阻塞的put和take方法,支持定時的offer和poll方法,如果隊列已經滿了,那麼put方法將阻塞直到有空間可用;如果隊列為空,那麼take方法將會阻塞直到有元素可用;同時隊列可以是有界也可以是無界的,無界隊列永遠都不會充滿,因此無界隊列的put方法永遠不會阻塞;
  • 從使用到原理,探究Java線程池
    當我們往線程池裡提交任務時,如果線程池內的線程數少於corePoolSize,則會直接創建新的線程處理任務;如果線程池的線程數達到了corePoolSize,並且存儲隊列沒滿,則會把任務放到workQueue任務存儲隊列裡;如果存儲隊列也滿了,但是線程數還沒有達到maxPoolSize,這個時候就會繼續創建線程執行任務
  • Java中線程池,你真的會用嗎?
    在文中有這樣一段描述:可以通過Executors靜態工廠構建線程池,但一般不建議這樣使用。關於這個問題,在那篇文章中並沒有深入的展開。作者之所以這麼說,是因為這種創建線程池的方式有很大的隱患,稍有不慎就有可能導致線上故障。本文我們就來圍繞這個問題來分析一下為什麼JDK自身提供的構建線程池的方式並不建議使用?
  • 深入理解 Java 線程池,講解的太清晰了
    在線程池處於 RUNNING 狀態時,調用 shutdown 方法會使線程池進入到該狀態。finalize 方法在執行過程中也會調用 shutdown 方法進入該狀態。RUNNING - 運行狀態。接受新任務,並且也能處理阻塞隊列中的任務。SHUTDOWN - 關閉狀態。不接受新任務,但可以處理阻塞隊列中的任務。STOP - 停止狀態。不接受新任務,也不處理隊列中的任務。會中斷正在處理任務的線程。
  • Java中常用隊列的總結
    當隊列滿的時候,在向隊列中添加元素會拋出異常;當隊列為空的時候在從隊列中刪除或者是獲取隊首元素都會拋出異常;帶有返回值的:添加元素:offer(e),刪除元素:poll(),檢查隊首元素:peek().
  • 「技術」其實銀行就是一個Java線程池
    最多七個櫃檯就叫做最大員工數有了新的員工,人多了,處理業務的速度也上來了,會出現兩種情況雖然銀行已經滿負載了,但是人還是源源不斷的來銀行辦業務,這個時候所有的工作人員都忙著,等待區也坐滿了人,那麼新的人怎麼辦呢?
  • 詳解 Tomcat 的連接數與線程池
    在Poller中,維護了一個Selector對象;當Poller從隊列中取出socket後,註冊到該Selector中;然後通過遍歷Selector,找出其中可讀的socket,並使用Worker中的線程處理相應請求。與BIO類似,Worker也可以被自定義的線程池代替。
  • 圖解 | 阿里巴巴面試官愛問的線程池到底是什麼?
    阻塞隊列線程池中的workQueue是一個阻塞隊列,用於存放線程池未能及時處理執行的任務。它的存在既解耦了任務的提交與執行,又能起到一個緩衝的作用。阻塞隊列有很多,下面我帶你了解一下常見的阻塞隊列。拒絕策略當任務隊列滿了之後,如果還有任務提交過來,會觸發拒絕策略,常見的拒絕策略有:AbortPolicy:丟棄任務並拋出異常,默認該方式。
  • 通過源碼解析,深入Java 線程池原理
    在這種情形下,我們可能不想將每個到來的請求都排隊到我們的工作隊列,因為排在隊列中等待執行的任務可能會消耗太多的系統資源並引起資源缺乏。在這種情形下決定如何做取決於您自己;在某些情況下,您可以簡單地拋棄請求,依靠更高級別的協議稍後重試請求,您也可以用一個指出伺服器暫時很忙的響應來拒絕請求。
  • JAVA 線程池ThreadPoolExcutor原理探究
    如果當阻塞隊列已滿時,並且當前線程池線程個數沒有超過 maximumPoolSize 的話,就會創建新的線程來執行任務。注意 maximumPoolSize >= 1 必須大於等於 1。maximumPoolSize == corePoolSize ,即是固定大小線程池。實際上最大容量是由 CAPACITY 控制。
  • 10分鐘了解線程池,阿里再也不擔心我線程池資源耗盡了
    newFixedThreadPool :定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。newScheduledThreadPool :計劃線程池,支持定時及周期性任務執行。MaximumPoolSize: 線程池中最大線程數。keepAliveTime:線程空閒時間超過,則會超時退出。BlockingQueue :設置一個阻塞用來存放將要執行的等待任務。
  • 「原創」Java並發編程系列33|深入理解線程池(上)
    線程池狀態RUNNING :能接受新提交的任務,並且也能處理阻塞隊列中的任務;SHUTDOWN:關閉狀態,不再接受新提交的任務,但卻可以繼續處理阻塞隊列中已保存的任務。在線程池處於 RUNNING 狀態時,調用 shutdown()方法會使線程池進入到該狀態。
  • Java並發編程系列34|深入理解線程池(下)
    6.1 execute()方法execute()方法執行過程如下:如果workerCount < corePoolSize,則創建並啟動一個線程來執行新提交的任務,即使有空閒線程,也要創建一個新線程;如果workerCount >= corePoolSize,且線程池內的阻塞隊列未滿,則將任務添加到該阻塞隊列中;如果workerCount >
  • 網際網路大廠:Java線程池實現原理及其在美團業務中的實踐
    任務管理部分充當生產者的角色,當任務提交後,線程池會判斷該任務後續的流轉:(1)直接申請線程執行該任務;(2)緩衝到隊列中等待線程執行;(3)拒絕該任務。線程管理部分是消費者,它們被統一維護在線程池內,根據任務請求進行線程的分配,當線程執行完任務後則會繼續獲取新的任務去執行,最終當線程獲取不到任務的時候,線程就會被回收。
  • 1000個並發線程,10臺機器,每臺機器4核,設計線程池大小
    (存放待執行任務的隊列:當提交的任務數超過核心線程數大小後,再提交的任務就存放在這裡。它僅僅用來存放被 execute 方法提交的 Runnable 任務。所以這裡就不要翻譯為工作隊列了,好嗎?不要自己給自己挖坑。)
  • java線程池核心類ThreadPoolExecutor概述
    JAVA中的阻塞隊列和非阻塞隊列我們介紹了常用的幾種隊列,隊列的使用很廣泛,特別是一些需要生產消費模式的場景以及需要對全局的集合進行操作的場景。:指定了線程池中的最大線程數量,這個參數會根據你使用的workQueue任務隊列的類型,決定線程池會開闢的最大線程數量;keepAliveTime:當線程池中空閒線程數量超過corePoolSize時,多餘的線程會在多長時間內被銷毀;unit:keepAliveTime
  • Java線程池其實看懂了也很簡單
    例如通過 newFixedThreadPool 方式創建的固定線程池,它內部使用的隊列是 LinkedBlockingQueue,但是它的隊列大小默認是 Integer.MAX_VALUE,這會有什麼問題?當核心線程滿了的時候,任務會進入隊列中等待,直到隊列滿了為止。
  • java並發編程之深入學習Concurrent包(十三,雙端阻塞隊列)
    上一章學習了阻塞隊列,這次一起學習下雙端阻塞隊列。LinkedBlockingDeque簡介:LinkedBlockingDeque是雙向鍊表實現的雙端阻塞隊列。該阻塞隊列可以從隊列的頭和尾進行插入和刪除,且該阻塞隊列是線程安全的。LinkedBlockingDeque分別繼承了隊列和雙端隊列的接口,如下所示:
  • 乾貨|兩萬字一次搞定線程池的實現原理
    線程池,顧名思義就是存放線程的池子,池子裡存放了很多可以復用的線程。7.handler任務拒絕策略,當阻塞隊列滿了,且線程池中的線程數達到maximumPoolSize,如果繼續提交任務,就會採取任務拒絕策略處理該任務,線程池提供了4種任務拒絕策略:AbortPolicy:丟棄任務並拋出RejectedExecutionException
  • Java入門 - - - 線程池的基本使用
    線程池的優點:加快響應速度(線程不必頻繁創建和銷毀);合理的利用CPU和內存這些有限資源;便於進行統一管理使用場景:比如伺服器接收大量請求時,或是開發過程中需要創建多個線程處理任務等。講解:核心類ThreadPoolExecutor。