天天看點

Java線程池原理全面詳解

作者:老吾頻道
Java線程池原理全面詳解

線程池作為一種池化技術,不僅在并發程式設計裡占據了非常重要的位置,也是大廠常問的内容了,流程原理?有什麼風險?等等,本篇就來談談這些線程池的關鍵點

01 為什麼需要線程池

如果需要處理大量任務,頻繁地建立和銷毀線程會浪費時間和效率,尤其是浪費記憶體。為了讓線程重複利用,讓它們繼續執行其他任務而不是立即銷毀,線程池應運而生。

線程池通過預先建立一定數量的線程,讓這些線程處理來自任務隊列中的任務,而不是頻繁建立和銷毀線程。任務執行完成後,線程不會被銷毀,而是放回線程池中以供下一次使用,這避免了頻繁建立和銷毀線程的開銷。同時,線程池還可以限制線程的數量,避免線程數量過多導緻資源競争、上下文切換等問題,進而提高程式的執行效率。

02 線程池的優點

1、線程是一種寶貴的資源,是以使用線程池可以減少建立和銷毀線程的次數,進而提高應用程式的性能。線程池中的工作線程可以重複利用,減少了線程的建立和銷毀開銷。

2、通過調整線程池中工作線程的數量,可以根據系統的承受能力來适配線程池,防止過多的記憶體消耗導緻伺服器崩潰。這可以提高應用程式的可靠性和穩定性。

03 線程池的使用風險

雖然線程池是建構多線程應用程式的強大機制,但使用它并不是沒有風險的。與其它多線程應用程式一樣,用線程池建構的應用程式容易遭受同步錯誤和死鎖等并發風險。此外,線程池還容易遭受特定的風險,如與池有關的死鎖、資源不足和線程洩漏。是以,在使用線程池時,需要特别注意線程安全和資源管理等問題,以充分發揮其優勢,避免遭受風險。

1.死鎖

死鎖是兩個或更多線程阻塞着等待其它處于死鎖狀态的線程所持有的鎖。

死鎖通常發生在多個線程同時但以不同的順序請求同一組鎖的時候。

Java線程池原理全面詳解

任何多線程應用程式都有死鎖風險。

2.資源不足

線程消耗包括記憶體和其他系統資源在内的大量資源。每個線程都需要兩個可能很大的執行調用堆棧,除了 Thread 對象所需的記憶體之外。此外,JVM 可能會為每個 Java 線程建立一個本機線程,這些本機線程将消耗額外的系統資源。

雖然線程之間切換的排程開銷很小,但如果有很多線程,環境切換也可能嚴重影響程式的性能。如果線程池太大,那麼被那些線程消耗的資源可能嚴重影響系統性能。同時,使用超出實際需要的線程可能會引起資源匮乏問題,因為池線程正在消耗一些資源,而這些資源可能會被其他任務更有效地利用。

除此以外,線程池建構的應用程式容易遭受任何其他多線程應用程式容易遭受的所有并發風險,諸如同步錯誤和死鎖,它還容易遭受特定于線程池的少數其他風險,諸如與池有關的死鎖、資源不足和線程洩漏。是以,在使用線程池時,需要仔細考慮和管理,以確定系統的穩定性和性能。

3.線程洩漏

線程洩漏是各種類型的線程池中的一個嚴重風險。當從線程池中取出一個線程以執行任務,但任務完成後該線程沒有傳回池時,就會發生線程洩漏。 一種常見情況是任務抛出 RuntimeException 或 Error 時未被捕獲。這時線程會退出,但線程池的大小将永久減少一個。如果這種情況發生次數足夠多,線程池最終會為空,系統将停止,因為沒有可用的線程來處理任務。

04 線程池的實作原理

Java線程池原理全面詳解

1.線程池狀态

線程池和線程一樣擁有自己的狀态,在ThreadPoolExecutor類中定義了一個volatile變量runState來表示線程池的狀态,線程池有四種狀态,分别為RUNNING、SHURDOWN、STOP、TERMINATED。

  1. 線程池建立後處于RUNNING狀态。
  2. 調用shutdown後處于SHUTDOWN狀态,線程池不能接受新的任務,會等待緩沖隊列的任務完成。
  3. 調用shutdownNow後處于STOP狀态,線程池不能接受新的任務,并嘗試終止正在執行的任務。
  4. 當線程池處于SHUTDOWN或STOP狀态,并且所有工作線程已經銷毀,任務緩存隊列已經清空或執行結束後,線程池被設定為TERMINATED狀态。

線程池原理:預先建立一定數量的線程,線程無限循環從任務隊列中擷取一個任務進行執行,直到線程池被關閉。如果某個線程因為執行某個任務發生異常而終止,那麼線程池會建立一個新的線程來替代它繼續執行任務,如此反複。

2.線程池的處理流程

Java線程池原理全面詳解

1、線程池會先判斷是否有空閑的核心線程,如果有則将任務配置設定給其中一個空閑的核心線程執行。如果沒有空閑的核心線程或者核心線程的數量還沒達到最大值,則建立一個新的核心線程來執行任務。如果核心線程已經達到最大值,則進入下一個流程。 2、如果工作隊列未滿,則将新送出的任務存儲在這個工作隊列中。如果工作隊列已滿,則會判斷線程池中的線程數是否已經達到最大值,如果沒有則建立一個新的非核心線程來執行任務。如果線程數已經達到最大值,則進入下一個流程。 3、如果線程池中的線程都已經處于工作狀态,即核心線程和非核心線程都在執行任務,則交給飽和政策來處理這個任務。飽和政策可以決定如何處理無法處理的任務,例如抛出異常或者阻塞任務送出。

Java線程池原理全面詳解