學好執行緒池,搞定高併發!(文末福利)
來源:JAVA日知錄
在真實高併發場景下,一般不會直接使用 Thread 類建立執行緒,而是使用執行緒池來建立並管理執行緒。可以這麼說,學好執行緒池對於併發程式設計是非常重要的。
01
執行緒池簡介
執行緒池的建立和回收是一個非常消耗系統資源的過程,如果在系統中頻繁地建立和回收執行緒,會極大降低程式的執行效能。並且,短時間內建立大量的執行緒可能造成 CPU 佔用 100%、當機或記憶體溢位等問題。而使用執行緒池就能非常輕鬆地解決這些問題。
執行緒池核心類繼承關係
執行緒池是 Java 從 JDK 1.5 版本開始提供的一種執行緒使用模式,能夠自動建立和回收執行緒,並管理執行緒的生命週期。線上程池中能夠管理和維護多個執行緒。
Java 的執行緒池主要是透過 Executor 框架實現的,涉及 Executor 介面、ExecutorServcie 介面、AbstractExecutorService 抽象類、ScheduledExecutorService 介面、ThreadPoolExecutor 類和ScheduledThreadPoolExecutor 類。執行緒池核心類繼承關係如下圖所示。
實現執行緒池最核心的類是ThreadPoolExecutor,而 ScheduledThreadPoolExecutor 類實現了定時任務功能,能夠使提交到執行緒池中的任務定時、定期執行。為了便於建立執行緒池,除了上圖所示的介面和類,JDK 還提供了一個 Executors 工具類,Executors 類中封裝了建立執行緒池的各種方法,專門用於建立執行緒池。不過,在真實的高併發場景下,並不推薦使用 Executors 工具類建立執行緒池,而是推薦直接使用 ThreadPoolExecutor 類建立執行緒池。
02
執行緒池的優點
這裡,綜合對比直接使用 Thread 類建立執行緒的弊端與使用執行緒池的優點,來加深讀者對執行緒池的理解。
1.直接使用 Thread 類建立執行緒的缺點
直接在程式中使用 Thread 類建立執行緒的方式是非常不可取的,主要體現在如下幾方面。
(1)每次透過 Thread 類建立一個執行緒物件的效能是非常差的,每次建立 Thread 物件後,呼叫 Thread 的 start()方法都會在作業系統層面分配一個與之對應的執行緒,這個過程比較耗時。
(2)直接使用 Thread 類建立執行緒缺乏有效的統一管理機制,如果在短時間內建立大量執行緒,執行緒之間就會競爭系統資源,可能造成 CPU 佔用 100%、當機或者記憶體溢位等問題。
(3)直接使用 Thread 類建立執行緒提供的執行緒功能非常有限,例如,無法讓執行緒執行更多的任務、無法定期執行某些任務等。
(4)直接使用 Thread 類建立執行緒,無法對執行緒進行有效監控。
2.使用執行緒池管理執行緒的優點
使用執行緒池能夠非常容易地解決直接使用 Thread 建立執行緒產生的問題,主要體現在如下幾方面。
(1)執行緒池能夠複用執行緒資源,有效減少了執行緒的建立和回收頻率,減少了執行緒的建立與回收對系統效能造成的影響,比直接使用 Thread 類建立執行緒的系統效能高。
(2)使用執行緒池能夠有效控制最大併發執行緒數,提高系統資源的利用率。建立的執行緒數是可控的,短時間內不會因為建立大量的執行緒導致執行緒過多地競爭資源,引起執行緒阻塞。
(3)線上程池中可以定時或定期執行某個或某些任務,提供了單執行緒執行任務的機制,也能夠控制併發執行緒數。執行緒池提供了監控執行緒資源的方法,可以對執行緒池中的執行緒資源進行實時監控。
03
ThreadPoolExecutor 類
ThreadPoolExecutor 是執行緒池中最核心的類,透過檢視 ThreadPoolExecutor 的程式碼可以得知,在使用 ThreadPoolExecutor 類的構造方法建立執行緒池時,最終會呼叫具有 7 個引數的構造方法,
程式碼如下。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler rejectHandler)
接下來,對 ThreadPoolExecutor 類構造方法中每個引數的具體含義進行簡單的介紹。
(1)corePoolSize 引數。表示執行緒池的核心執行緒數。
(2)maximumPoolSize 引數。表示執行緒池中的最大執行緒數。
(3)keepAliveTime 引數。表示執行緒沒有任務執行狀態保持的最長時間。當執行緒池中的執行緒數量大於 corePoolSize 時,如果沒有新的任務提交,則核心執行緒外的執行緒不會立即銷燬,需要等待,直到等待的時間超過 keepAliveTime 才會終止。
(4)unit 引數。表示 keepAliveTime 的時間單位。
(5)workQueue 引數。表示執行緒池中的阻塞佇列,儲存等待執行的任務。
(6)threadFactory 引數。執行緒工廠,用來建立執行緒池中的執行緒。提供一個預設的執行緒工廠來建立執行緒,當使用預設的執行緒工廠建立執行緒時,會為執行緒設定一個名稱,使新建立的執行緒具有相同的優先順序,並且是非守護執行緒。
(7)rejectHandler 引數。表示拒絕處理任務時的策略。當 workQueue 阻塞佇列已滿、執行緒池中的執行緒數已經達到最大,且執行緒池中沒有空閒執行緒時,如果繼續提交任務,就需要採取一種策略來處理這個任務。
其中,在 ThreadPoolExecutor 類的構造方法中,最重要的 3 個引數是 corePoolSize、maximumPoolSize 和 workQueue,這 3 個引數會對執行緒池的執行過程產生重大的影響。
三者的關係如下
如果執行緒池中執行的執行緒數小於 corePoolSize,則直接建立新執行緒處理任務,即使執行緒池中的其他執行緒是空閒的。
如果執行的執行緒數大於或等於 corePoolSize 並且小於 maximumPoolSize,則只有當workQueue 佇列滿時,才會建立新的執行緒處理任務。如果 workQueue 佇列不滿,則將新提交的任務放入 workQueue 佇列中。當設定的 corePoolSize 與 maximumPoolSize 相同時,建立的執行緒池大小是固定的,如果滿足有新任務提交、執行緒池中沒有空閒執行緒,且 workQueue 未滿的條件,就把請求放入workQueue,等待空閒的執行緒從 workQueue 中取出任務進行處理。
如果執行的執行緒數量大於 maximumPoolSize,同時 workQueue 已滿,則透過拒絕策略參數 rejectHandler 來指定處理策略。
執行緒池提供了 4 種拒絕策略,分別如下。
直接丟擲異常,這也是預設的策略。實現類為 AbortPolicy。
使用呼叫者所在的執行緒來執行任務。實現類為 CallerRunsPolicy。
丟棄佇列中最靠前的任務並執行當前任務。實現類為 DiscardOldestPolicy。
直接丟棄當前任務。實現類為 DiscardPolicy。
本文節選自《深入理解高併發程式設計:JDK核心技術》一書,本書是冰河編寫的專注介紹JDK高併發程式設計技術的書籍。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2942860/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 66.QT-執行緒併發、QTcpServer併發、QThreadPool執行緒池QT執行緒TCPServerthread
- Java併發——執行緒池ThreadPoolExecutorJava執行緒thread
- Java併發系列 — 執行緒池Java執行緒
- 聊聊併發(五)——執行緒池執行緒
- 解密TaurusDB儲存端高併發之執行緒池解密執行緒
- 高併發面試:執行緒池的七大引數?手寫一個執行緒池?面試執行緒
- Java 併發:執行緒、執行緒池和執行器全面教程Java執行緒
- java多執行緒與併發 - 執行緒池詳解Java執行緒
- epoll程式設計,單epoll+執行緒池?執行緒池+epoll?nginx實現高併發的原理?程式設計執行緒Nginx
- Java併發 之 執行緒池系列 (2) 使用ThreadPoolExecutor構造執行緒池Java執行緒thread
- Java併發 之 執行緒池系列 (1) 讓多執行緒不再坑爹的執行緒池Java執行緒
- 多執行緒與高併發(二)執行緒安全執行緒
- 【重學Java】多執行緒進階(執行緒池、原子性、併發工具類)Java執行緒
- nodejs 單執行緒 高併發NodeJS執行緒
- Java併發基礎(2)------執行緒池Java執行緒
- java併發程式設計——執行緒池Java程式設計執行緒
- golang 限流器,控制併發,執行緒池Golang執行緒
- Java併發之執行緒池ThreadPoolExecutor原始碼分析學習Java執行緒thread原始碼
- Java併發程式設計學習筆記----執行緒池Java程式設計筆記執行緒
- 併發07--執行緒池及Executor框架執行緒框架
- Java併發程式設計:執行緒池ThreadPoolExecutorJava程式設計執行緒thread
- 併發程式設計之:執行緒池(一)程式設計執行緒
- 多執行緒與高併發(一)多執行緒入門執行緒
- 《java學習三》併發程式設計 -------執行緒池原理剖析Java程式設計執行緒
- 《Java 高階篇》七:執行緒和執行緒池Java執行緒
- 【高併發】從原始碼角度分析建立執行緒池究竟有哪些方式原始碼執行緒
- 【高併發】不得不說的執行緒池與ThreadPoolExecutor類淺析執行緒thread
- 【多執行緒與高併發】- 執行緒基礎與狀態執行緒
- 【python高併發】程序、執行緒的理解Python執行緒
- 執行緒池學習執行緒
- 深入併發之(四) 執行緒池詳細分析執行緒
- Java併發包中執行緒池ThreadPoolExecutor原理探究Java執行緒thread
- Java 併發程式設計 | 執行緒池詳解Java程式設計執行緒
- java併發程式設計:執行緒池的使用Java程式設計執行緒
- 併發程式設計之:深入解析執行緒池程式設計執行緒
- 【高併發】深入理解執行緒的執行順序執行緒
- Java高併發與多執行緒(二)-----執行緒的實現方式Java執行緒
- 【多執行緒與高併發】- 淺談volatile執行緒