線程池七個參數的含義

Java中的線程池里七個參數的以及其各自的含義

面試題:說一下線程池七個參數的含義?

所謂的線程池的 7 大參數是指,在使用 ThreadPoolExecutor 創建線程池時所設置的 7 個參數,如以下源碼所示:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {
}

這 7 個參數分別是:

  1. corePoolSize:核心線程數。
  2. maximumPoolSize:最大線程數。
  3. keepAliveTime:空閑線程存活時間。
  4. TimeUnit:時間單位。
  5. BlockingQueue:線程池任務隊列。
  6. ThreadFactory:創建線程的工廠。
  7. RejectedExecutionHandler:拒絕策略。

參數1:corePoolSize

核心線程數:是指線程池中長期存活的線程數。

這就好比古代大戶人家,會長期雇傭一些“長工”來給他們干活,這些人一般比較穩定,無論這一年的活多活少,這些人都不會被辭退,都是長期生活在大戶人家的。

參數2:maximumPoolSize

最大線程數:線程池允許創建的最大線程數量,當線程池的任務隊列滿了之后,可以創建的最大線程數。

這是古代大戶人家最多可以雇傭的人數,比如某個節日或大戶人家有人過壽時,因為活太多,僅靠“長工”是完不成任務,這時就會再招聘一些“短工”一起來干活,這個最大線程數就是“長工”+“短工”的總人數,也就是招聘的人數不能超過 maximumPoolSize。

注意事項

最大線程數 maximumPoolSize 的值不能小于核心線程數 corePoolSize,否則在程序運行時會報 IllegalArgumentException 非法參數異常,如下圖所示:
在這里插入圖片描述

參數3:keepAliveTime

空閑線程存活時間,當線程池中沒有任務時,會銷毀一些線程,銷毀的線程數=maximumPoolSize(最大線程數)-corePoolSize(核心線程數)。

還是以大戶人家為例,當大戶人家比較忙的時候就會雇傭一些“短工”來干活,但等干完活之后,不忙了,就會將這些“短工”辭退掉,而 keepAliveTime 就是用來描述沒活之后,短工可以在大戶人家待的(最長)時間。

參數4:TimeUnit

時間單位:空閑線程存活時間的描述單位,此參數是配合參數 3 使用的。參數 3 是一個 long 類型的值,比如參數 3 傳遞的是 1,那么這個 1 表示的是 1 天?還是 1 小時?還是 1 秒鐘?是由參數 4 說了算的。TimeUnit 有以下 7 個值:

  • TimeUnit.DAYS:天
  • TimeUnit.HOURS:小時
  • TimeUnit.MINUTES:分
  • TimeUnit.SECONDS:秒
  • TimeUnit.MILLISECONDS:毫秒
  • TimeUnit.MICROSECONDS:微妙
  • TimeUnit.NANOSECONDS:納秒

參數5:BlockingQueue

在Java中,BlockingQueue是一個接口,它的實現類有ArrayBlockingQueue、DelayQueue、 LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue等,它們的區別主要體現在存儲
結構上或對元素操作上的不同,但是對于take與put操作的原理,卻是類似的,目的都是阻塞存取。

有界與無界

有界隊列:就是有固定大小的隊列。比如設定了固定大小的 LinkedBlockingQueue,又或者大小為 0,只是在生產者和消費者中做中轉用的 SynchronousQueue。

無界隊列:指的是沒有設置固定大小的隊列。這些隊列的特點是可以直接入列,直到溢出。當然現實幾乎不會有到這么大的容量(超過 Integer.MAX_VALUE),所以從使用者的體驗上,就相當于 “無界”。比如沒有設定固定大小的 LinkedBlockingQueue。

阻塞與非阻塞

阻塞和非阻塞指的是調用者(程序)在等待返回結果(或輸入)時的狀態。阻塞時,在調用結果返回前,當前線程會被掛起,并在得到結果之后返回。非阻塞時,如果不能立刻得到結果,則該調用者不會阻塞當前線程。因此對應非阻塞的情況,調用者需要定時輪詢查看處理狀態。

入隊

add(E e):(非阻塞)調用offer但會根據offer結果,如果false拋出 IllegalStateException(“Queue full”)
offer(E e):(非阻塞)如果隊列沒滿,立即返回true; 如果隊列滿了,立即返回false
put(E e):(阻塞)如果隊列滿了,一直阻塞,直到隊列不滿了或者線程被中斷
offer(E e, long timeout, TimeUnit unit):在隊尾插入一個元素,,如果隊列已滿,則進入等待,直到出現以下三種情況:
1.被喚醒
2.等待時間超時
3.當前線程被中斷

出隊

poll():(非阻塞)如果沒有元素,直接返回null;如果有元素,出隊
remove():(非阻塞)刪除隊列頭元素,如果沒有元素,返回false
take():(阻塞)如果隊列空了,一直阻塞,直到隊列不為空或者線程被中斷
poll(long timeout, TimeUnit unit):如果隊列不空,出隊;如果隊列已空且已經超時,返回null;如果隊列已空且時間未超時,則進入等待,直到出現以下三種情況:
1.被喚醒
2.等待時間超時
3.當前線程被中斷

查看元素

element(): 調用peek(),查看元素,拿到為null,拋出 NoSuchElementException。
peek():查看元素,不去除,如果拿不到則為null。

阻塞隊列

阻塞隊列:是一種特殊的隊列,它在普通隊列的基礎上提供了兩個附加功能。
在這里插入圖片描述

即:

  1. 當隊列為空的時候,獲取隊列中元素的消費者線程會被阻塞,同時喚醒生產者線程。
  2. 當隊列滿了的時候,向隊列中添加元素的生產者線程被阻塞,同時喚醒消費者線程。

在線程池中,阻塞隊列是用來存儲線程池的所有待執行任務的隊列。它可以設置以下幾個值:

- ArrayBlockingQueue:一個由數組結構組成的有界阻塞隊列。特點:ArrayBlockingQueue底層是使用一個數組實現隊列的,內部使用了一把鎖對插入和取出做了限制,即插或者取的操作是原子性容量:需要指定一個大小,創建了無法修改元素:不允許為null的元素插入
- LinkedBlockingQueue:一個由鏈表結構組成的有界阻塞隊列。特點:內部有兩把鎖,即入隊鎖和出隊鎖(ReentrantLock+Condition),插入和取出各一把,互不打擾。兩把鎖來控制插入和取出數組阻塞喚醒。內部通過AtomicInteger count變量保證統計隊列元素準確容量:默認為Integer.MAX_VALUE元素:不允許為null的元素插入
- SynchronousQueue:一個不存儲元素的阻塞隊列,即直接提交給線程不保持它們。一種無緩沖的等待隊列,相對于有緩沖的BlockingQueue來說,少了一個中間經銷商的環節(緩沖區)。消費者必須親自去集市找到所要商品的直接生產者特點:一對一,生產者和消費者缺一就阻塞,存在公平和非公平兩種容量:size默認為0,剩余容量也為0元素:不允許為null的元素插入
- PriorityBlockingQueue:一個支持優先級排序的無界阻塞隊列。特點:無界隊列依賴Comparator來確保不同元素的排序位置,最大值不超過Integer.MAX_Value-8容量:默認大小為11,底層使用數組來存儲,會擴容元素:不允許為null的元素插入
- DelayQueue:一個使用優先級隊列實現的無界阻塞隊列,只有在延遲期滿時才能從中提取元素。特點:存儲Delayed元素,可實現延時等功能容量:默認為11,底層使用PriorityBlockingQueue來存儲元素:不允許為null的元素插入,內部存儲Delay的實現類元素take:內部使用priorityblockingqueue排序,根據getDelay判斷剩余時間,只有當前到點了,才可以取出元素
- LinkedBlockingDeque:一個由鏈表結構組成的雙向阻塞隊列。特點:BlockingDeque 類是一個雙端隊列,在不能夠插入元素時,它將阻塞住試圖插入元素的線程;在不能夠抽取元素時,它將阻塞住試圖抽取的線程。容量:可以指定隊列的容量(防止過度膨脹),如果不指定,默認容量大小等于Integer.MAX_VALUE。元素:同時支持FIFO和FILO兩種操作方式(即可以從隊列的頭和尾同時操作(插入/刪除)),支持線程安全。
- LinkedTransferQueue:一個由鏈表結構組成的無界阻塞隊列。與SynchronousQueue類似,還含有非阻塞方法。public interface TransferQueue<E> extends BlockingQueue<E> {// 如果可能,立即將元素轉移給等待的消費者。 // 如果存在消費者已經等待接收它(在 take 或 timed poll(long,TimeUnit)poll)中,則立即傳送指定的元素,否則返回 false。boolean tryTransfer(E e);// 將元素轉移給消費者,如果需要的話等待。 // 如果存在一個消費者已經等待接收它(在 take 或timed poll(long,TimeUnit)poll)中,則立即傳送指定的元素,否則等待直到元素由消費者接收。void transfer(E e) throws InterruptedException;// 上面方法的基礎上設置超時時間boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException;// 如果至少有一位消費者在等待,則返回 trueboolean hasWaitingConsumer();// 返回等待消費者人數的估計值int getWaitingConsumerCount();}特點:實現了TransferQueue接口。TransferQueue接口繼承了BlockingQueue,主要擴展了兩個方法tryTransfer、transfer。對比:和SynchronousQueue.TransferQueue(公平模式)相比,它是可以統計長度,可以進行查詢的;和LinkedBlockingQueue相比,它擁有更高的性能(使用CAS自旋);和ConcurrentLinkedQueue相比,它擁有阻塞功能。因此可以看作是ConcurrentLinkedQueue、SynchronousQueue、LinkedBlockingQueue的超集,作為對比學習。既然說到了,那就順便說一下ConcurrentLinkedQueue吧。總結:ArrayBlockingQueue:需要創建隊列數組長度。LinkedBlockingQueue:內部使用Node實現,默認大小Integer.MAX_VALUE。PriorityBlockingQueue:優先級隊列,默認大小11,內部需實現Comparator來比較。DelayQueue:延時隊列,元素需要實現Delayed,底層使用PriorityBlockingQueue,默認大小11。SynchronousQueue:交換隊列,默認大小0,需同時存在生產者和消費者,否則任一都會阻塞LinkedTransferQueue:新增transfer方法,tryTransfer和transfer可以檢測是否有線程在等待獲取數據,如果檢測到就立即發送新增的數據給這個線程獲取而不用放入隊列。
-----------------------------------------------------------------------------------------	
順便提一下ConcurrentLinkedQueue。
- ConcurrentLinkedQueue:是一種非阻塞的無界的線程安全隊列,與阻塞隊列LinkedBlockingQueue相對應,ConcurrentLinkedQueue同樣也是使用鏈表實現的FIFO隊列,但不同的是它沒有使用任何鎖機制,而是用自旋+CAS來實現線程安全。特點:
.不允許null入列
.在入隊的最后一個元素的next為null
.隊列中所有未刪除的節點的item都不能為null且都能從head節點遍歷到
.刪除節點是將item設置為null, 隊列迭代時跳過item為null節點
.head節點跟tail不一定指向頭節點或尾節點,可能存在滯后性 

比較常用的是 LinkedBlockingQueue,線程池的排隊策略和 BlockingQueue 息息相關。

參數6:ThreadFactory

線程工廠:線程池創建線程時調用的工廠方法,通過此方法可以設置線程的優先級、線程命名規則以及線程類型(用戶線程還是守護線程)等。線程工廠的使用示例如下:

public static void main(String[] args) {// 創建線程工廠ThreadFactory threadFactory = new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {// 創建線程池中的線程Thread thread = new Thread(r);// 設置線程名稱thread.setName("Thread-" + r.hashCode());// 設置線程優先級(最大值:10)thread.setPriority(Thread.MAX_PRIORITY);//......return thread;}};// 創建線程池ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 0,TimeUnit.SECONDS, new LinkedBlockingQueue<>(),threadFactory); // 使用自定義的線程工廠threadPoolExecutor.submit(new Runnable() {@Overridepublic void run() {Thread thread = Thread.currentThread();System.out.println(String.format("線程:%s,線程優先級:%d",thread.getName(), thread.getPriority()));}});
}

以上程序的執行結果如下:

在這里插入圖片描述

從上述執行結果可以看出,自定義線程工廠起作用了,線程的名稱和線程的優先級都是通過線程工廠設置的。

參數7:RejectedExecutionHandler

拒絕策略:當線程池的任務超出線程池隊列可以存儲的最大值之后,執行的策略。默認的拒絕策略有以下 4 種:

  • AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。
  • CallerRunsPolicy:使用當前調用的線程來執行此任務。
  • DiscardOldestPolicy:丟棄隊列頭部(最舊)的一個任務,并重新執行當前任務(重復此過程)。
  • DiscardPolicy:也是丟棄任務,但是不拋出異常。

線程池的默認策略是 AbortPolicy 拒絕并拋出異常。

案例分析

線程池中線程數小于corePoolSize時,新任務將創建一個新線程執行任務,不論此時線程池中是否存在空閑線程。

線程池中線程數達到corePoolSize時,新任務將被放入workQueue中,等待線程池中任務調度執行;

當workQueue已滿,且maximumPoolSize>corePoolSize時,新任務會創建新線程執行任務;

當workQueue已滿,且提交任務數超過maximumPoolSize,任務由RejectedExecutionHandler處理;

當線程池中線程數超過corePoolSize,且超過這部分的空閑時間達到keepAliveTime時,回收該線程;

如果設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize范圍內的線程空閑時間達到keepAliveTime也將回收;

總結

本文介紹了線程池的 7 大參數:

  1. corePoolSize:核心線程數,線程池正常情況下保持的線程數,大戶人家“長工”的數量。
  2. maximumPoolSize:最大線程數,當線程池繁忙時最多可以擁有的線程數,大戶人家“長工”+“短工”的總數量。
  3. keepAliveTime:空閑線程存活時間,沒有活之后“短工”可以生存的最大時間。
  4. TimeUnit:時間單位,配合參數 3 一起使用,用于描述參數 3 的時間單位。
  5. BlockingQueue:線程池的任務隊列,用于保存線程池待執行任務的容器。
  6. ThreadFactory:線程工廠,用于創建線程池中線程的工廠方法,通過它可以設置線程的命名規則、優先級和線程類型。
  7. RejectedExecutionHandler:拒絕策略,當任務量超過線程池可以保存的最大任務數時,執行的策略。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79480.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79480.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79480.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【最后203篇系列】028 FastAPI的后臺任務處理

說明 今天偶然在別的文章里看到這個功能&#xff0c;突然覺得正好。 CeleryWorker已經搭好了&#xff0c;但是我一直想在用戶請求時進行額外的處理會比較影響處理時間&#xff0c;用這個正好可以搭配上。 我設想的一個場景&#xff1a; 1 用戶發起請求2 接口中進行關鍵信息…

uboot下讀取ubifs分區的方法

在uboot 的defconfig中增加以下內容&#xff1a; CONFIG_MTDIDS_DEFAULT"nand0nand0" CONFIG_MTDPARTS_DEFAULT"mtdpartsnand0:1M(boot1),1M(boot2),1M(hwinfo),6M(kernel1),6M(kernel2),56M(rootfs1),56M(rootfs2),-(ubi2)" CONFIG_CMD_UBIy 其中&#x…

圖+文+語音一體化:多模態合成數據集構建的實戰與方法論

目錄 圖文語音一體化&#xff1a;多模態合成數據集構建的實戰與方法論 一、多模態合成數據的核心價值 二、系統架構概覽 三、核心模塊與實現建議 ? 1. 文→圖&#xff1a;圖像合成&#xff08;Text-to-Image&#xff09; ? 2. 圖→文&#xff1a;自動描述&#xff08;I…

linux驅動之poll

驅動中 poll 實現 在用戶空間實現事件操作的一個主要實現是調用 select/poll/epoll 函數。那么在驅動中怎么來實現 poll 的底層呢&#xff1f; 其實在內核的 struct file_operations 結構體中有一個 poll 成員&#xff0c;其就是底層實現的接口函數。 驅動中 poll 函數實現原…

第八篇:系統分析師第三遍——3、4章

目錄 一、目標二、計劃三、完成情況四、意外之喜(最少2點)1.計劃內的明確認知和思想的提升標志2.計劃外的具體事情提升內容和標志 五、總結 一、目標 通過參加考試&#xff0c;訓練學習能力&#xff0c;而非單純以拿證為目的。 1.在復習過程中&#xff0c;訓練快速閱讀能力、掌…

C++17 新特性簡解

C17 新特性簡解 一、核心語言特性 1. 結構化綁定&#xff08;Structured Bindings&#xff09; 用途&#xff1a;解構復合類型&#xff08;如元組、結構體&#xff09;為獨立變量 示例&#xff1a; #include <iostream> #include <tuple>int main() {// 解構 st…

PHP使用pandoc把markdown文件轉為word

文章目錄 首先安裝pandocPHP處理 服務器操作系統是Linux&#xff0c;centos 首先安裝pandoc yum install -y pandoc安裝完成后輸入如下代碼&#xff0c;檢查安裝是否成功 pandoc --versionPHP處理 我把markdown內容存到了數據庫里&#xff0c;所以要從數據庫讀取內容。對內容…

【Python學習筆記】Pandas實現Excel質檢記錄表初審、復核及質檢統計

背景&#xff1a; 我有這樣一個需要審核的飛書題目表&#xff0c;按日期分成多個sheet&#xff0c;有初審——復核——質檢三個環節&#xff0c;這三個環節是不同的同學在作業&#xff0c;并且領到同一個題目的人選是隨機的&#xff0c;也就是說&#xff0c;完成一道題的三個人…

守護進程編程、GDB調試以及外網連接樹莓派

目錄 一、什么是守護進程以及如何創建守護進程1. 什么是守護進程&#xff1f;2. 如何創建守護進程&#xff1f; 二、什么是GDB調試以及如何用GDB命令調試C程序1. 什么是GDB&#xff1f;2. 如何用GDB命令調試C程序&#xff1f; 三、外網訪問樹莓派 一、什么是守護進程以及如何創…

Logisim數字邏輯實訓——計數器設計與應用

4位遞增計數器 六進制計數器 十進制計數器 六十進制計數器 二十四進制計數器 計時器

發現“橫”字手寫有難度,對比兩個“橫”字

我發現手寫體“橫”字“好看”程度&#xff0c;難以比得上印刷體&#xff1a; 兩個從方正簡體啟體來的“橫”字&#xff1a; 哪個更好看&#xff1f;我是傾向于左邊一點。 <div style"transform: rotate(180deg); display: inline-block;"> 左邊是我從方正簡…

ubuntu 向右拖動窗口后消失了、找不到了

這是目前單顯示器的設置&#xff0c;因為實際只有1個顯示器&#xff0c;之前的設置如下圖所示&#xff0c;有2個顯示器&#xff0c;一個主顯示器&#xff0c;一個23寸的顯示器 ubuntu 22.04 系統 今天在操作窗口時&#xff0c;向右一滑&#xff0c;發現這個窗口再也不顯示了、找…

專精特新政策推動,B端UI設計如何賦能中小企業創新發展?

在當前數字化轉型浪潮下&#xff0c;專精特新政策為中小企業提供了強大的支持&#xff0c;助力其在細分領域實現專業化、精細化、特色化和創新化發展。B端UI設計作為提升企業數字化產品用戶體驗和工作效率的重要手段&#xff0c;能夠有效賦能中小企業創新發展。本文將探討專精特…

梯度下降代碼

整體流程 數據預處理:標準化->加一列全為1的偏置項 訓練:梯度下降,將數學公式轉換成代碼 預測 模型代碼 import numpy as np# 標準化函數&#xff1a;對特征做均值-方差標準化 # 返回標準化后的特征、新數據的均值和標準差&#xff0c;用于后續預測def standard(feats…

RAG 實戰|用 StarRocks + DeepSeek 構建智能問答與企業知識庫

文章作者&#xff1a; 石強&#xff0c;鏡舟科技解決方案架構師 趙恒&#xff0c;StarRocks TSC Member &#x1f449; 加入 StarRocks x AI 技術討論社區 https://mp.weixin.qq.com/s/61WKxjHiB-pIwdItbRPnPA RAG 和向量索引簡介 RAG&#xff08;Retrieval-Augmented Gen…

從零開始學A2A一:A2A 協議的高級應用與優化

A2A 協議的高級應用與優化 學習目標 掌握 A2A 高級功能 理解多用戶支持機制掌握長期任務管理方法學習服務性能優化技巧 理解與 MCP 的差異 分析多智能體場景下的優勢掌握不同場景的選擇策略 第一部分&#xff1a;多用戶支持機制 1. 用戶隔離架構 #mermaid-svg-Awx5UVYtqOF…

【C++】入門基礎【上】

目錄 一、C的發展歷史二、C學習書籍推薦三、C的第一個程序1、命名空間namespace2、命名空間的使用3、頭文件<iostream>是干什么的&#xff1f; 個人主頁<—請點擊 C專欄<—請點擊 一、C的發展歷史 C的起源可以追溯到1979年&#xff0c;當時Bjarne Stroustrup(本…

1panel第三方應用商店(本地商店)配置和使用

文章目錄 引言資源網站實戰操作說明 引言 1Panel 提供了一個應用提交開發環境&#xff0c;開發者可以通過提交應用的方式將自己的應用推送到 1Panel 的應用商店中&#xff0c;供其他用戶使用。由此衍生了一種本地應用商店的概念&#xff0c;用戶可以自行編寫應用配置并上傳到自…

Evidential Deep Learning和證據理論教材的區別(主要是概念)

最近終于徹底搞懂了Evidential Deep Learning&#xff0c;之前有很多看不是特別明白的地方&#xff0c;原來是和證據理論教材&#xff08;是的&#xff0c;不只是國內老師寫的&#xff0c;和國外的老師寫的教材出入也比較大&#xff09;的說法有很多不一樣&#xff0c;所以特地…

text-decoration: underline;不生效

必須得紀念一下&#xff0c;在給文本加下劃線時&#xff0c;發現在win電腦不生效&#xff0c;部分mac也不生效&#xff0c;只有個別的mac生效了&#xff0c;思考了以下幾種方面&#xff1a; 1.兼容性問題&#xff1f; 因為是electron項目&#xff0c;不存在瀏覽器兼容性問題&…