當前位置:首頁 » 硬碟大全 » 線程池緩存隊列數
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

線程池緩存隊列數

發布時間: 2023-01-03 10:41:37

㈠ 線程池七大核心參數

線程池七大核心參數如下所示:

一、corePoolSize 線程池核心線程大小

線程池中會維護一個最小的線程數量,即使這些線程處理空閑狀態,他們也不會被銷毀,除非設置了allowCoreThreadTimeOut。這里的最小線程數量即是corePoolSize。任務提交到線程池後,首先會檢查當前線程數是否達到了corePoolSize,如果沒有達到的話,則會創建一個新線程來處理這個任務。

二、maximumPoolSize 線程池最大線程數量

當前線程數達到corePoolSize後,如果繼續有任務被提交到線程池,會將任務緩存到工作隊列(後面會介紹)中。如果隊列也已滿,則會去創建一個新線程來出來這個處理。線程池不會無限制的去創建新線程,它會有一個最大線程數量的限制,這個數量即由maximunPoolSize指定。

三、keepAliveTime 空閑線程存活時間

一個線程如果處於空閑狀態,並且當前的線程數量大於corePoolSize,那麼在指定時間後,這個空閑線程會被銷毀,這里的指定時間由keepAliveTime來設定。

四、unit 空閑線程存活時間單位

空閑線程存活時間單位是keepAliveTime的計量單位。

五、workQueue 工作隊列

新任務被提交後,會先進入到此工作隊列中,任務調度時再從隊列中取出任務。

六、threadFactory 線程工廠

創建一個新線程時使用的工廠,可以用來設定線程名、是否為daemon線程等等。

七、handler 拒絕策略

當工作隊列中的任務已到達最大限制,並且線程池中的線程數量也達到最大限制,這時如果有新任務提交進來,該如何處理呢。這里的拒絕策略,就是解決這個問題的。

線程池的優勢

1、線程和任務分離,提升線程重用性;

2、控制線程並發數量,降低伺服器壓力,統一管理所有線程;

3、提升系統響應速度,假如創建線程用的時間為T1,執行任務用的時間為T2,銷毀線程用的時間為T3,那麼使用線程池就免去了T1和T3的時間。

㈡ 4種線程池和7種並發隊列

Java並發包中的阻塞隊列一共7個,當然他們都是線程安全的。 

ArrayBlockingQueue:一個由數組結構組成的 有界 阻塞隊列。 

LinkedBlockingQueue:一個由鏈表結構組成的無界阻塞隊列。 

PriorityBlockingQueue:一個支持優先順序排序的無界阻塞隊列。 

DealyQueue:一個使用優先順序(啟動時間)隊列實現的無界阻塞隊列。 

SynchronousQueue:一個不存儲元素的阻塞隊列。 

LinkedTransferQueue:一個由鏈表結構組成的無界阻塞隊列。 

LinkedBlockingDeque:一個由鏈表結構組成的雙向阻塞隊列。

常用的只有三個,重點是前兩個

LinkedBlockingQueue和ArrayBlockingQueue區別:

1、LinkedBlockingQueue內部由兩個ReentrantLock來實現出入隊列的線程安全,由各自的Condition對象的await和signal來實現等待和喚醒功能。而ArrayBlockingQueue的只使用一個ReentrantLock管理進出隊列。

而LinkedBlockingQueue實現的隊列中的鎖是分離的,其添加採用的是putLock,移除採用的則是takeLock,這樣能大大提高隊列的吞吐量,也意味著在高並發的情況下生產者和消費者可以並行地操作隊列中的數據,以此來提高整個隊列的並發性能。

2、隊列大小有所不同,ArrayBlockingQueue是有界的初始化必須指定大小,而LinkedBlockingQueue可以是有界的也可以是無界的(Integer.MAX_VALUE),對於後者而言,當添加速度大於移除速度時,在無界的情況下,可能會造成內存溢出等問題。

3、數據存儲容器不同,ArrayBlockingQueue採用的是數組作為數據存儲容器,而LinkedBlockingQueue採用的則是以Node節點作為連接對象的鏈表。

由於ArrayBlockingQueue採用的是數組的存儲容器,因此在插入或刪除元素時不會產生或銷毀任何額外的對象實例,而LinkedBlockingQueue則會生成一個額外的Node對象。這可能在長時間內需要高效並發地處理大批量數據的時,對於GC可能存在較大影響。

SynchronousQueue

沒有容量,是無緩沖等待隊列,是一個不存儲元素的阻塞隊列,會直接將任務交給消費者,必須等隊列中的添加元素被消費後才能繼續添加新的元素

使用SynchronousQueue阻塞隊列一般要求maximumPoolSizes為無界,避免線程拒絕執行操作。

1、newfixed,線程默認大小確定、最大大小確定(實際沒什麼用),默認使用linkedblockqueue,無盡隊列

危害在於這個等待隊列,隊列如果消費不及時不斷膨脹可以使機器資源耗盡

ArrayBlockingQueue是一個有界緩存等待隊列,可以指定緩存隊列的大小,當正在執行的線程數等於corePoolSize時,多餘的元素緩存在ArrayBlockingQueue隊列中等待有空閑的線程時繼續執行,當ArrayBlockingQueue已滿時,加入ArrayBlockingQueue失敗,會開啟新的線程去執行,當線程數已經達到最大的maximumPoolSizes時,再有新的元素嘗試加入ArrayBlockingQueue時會報錯。

2、cached,線程數不限大小

危害 本身就是沒有限制,有多少請求創建多少線程,直到資源耗盡

CachedThreadPool使用沒有容量的SynchronousQueue作為主線程池的工作隊列,它是一個沒有容量的阻塞隊列。每個插入操作必須等待另一個線程的對應移除操作。這意味著,如果主線程提交任務的速度高於線程池中處理任務的速度時,CachedThreadPool會不斷創建新線程。極端情況下,CachedThreadPool會因為創建過多線程而耗盡CPU資源。

3、single

可順序執行任務,同時只有一個線程處理(單線程)

執行過程如下:

1.如果當前工作中的線程數量少於corePool的數量,就創建一個新的線程來執行任務。

2.當線程池的工作中的線程數量達到了corePool,則將任務加入LinkedBlockingQueue。

3.線程執行完1中的任務後會從隊列中去任務。

注意:由於在線程池中只有一個工作線程,所以任務可以按照添加順序執行。

4、ScheledThreadPool

public ScheledThreadPoolExecutor(int corePoolSize) {

        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,

              new DelayedWorkQueue());

    }

使用了延遲隊列,無界,和cached類似

如果運行的線程達到了corePoolSize,就把任務添加到任務隊列DelayedWorkQueue中;DelayedWorkQueue會將任務排序,先執行的任務放在隊列的前面。

任務執行完後,ScheledFutureTask中的變數time改為下次要執行的時間,並放回到DelayedWorkQueue中

DelayQueue是一個沒有邊界BlockingQueue實現,加入其中的元素必需實現Delayed介面。 當生產者線程調用put之類的方法加入元素時,會觸發Delayed介面中的compareTo方法進行排序,也就是說隊列中元素的順序是按到期時間排序的,而非它們進入隊列的順序。排在隊列頭部的元素是最早到期的,越往後到期時間赿晚。

消費者線程查看隊列頭部的元素,注意是查看不是取出。然後調用元素的getDelay方法,如果此方法返回的值小0或者等於0,則消費者線程會從隊列中取出此元素,並進行處理。如果getDelay方法返回的值大於0,則消費者線程wait返回的時間值後,再從隊列頭部取出元素,此時元素應該已經到期。

DelayQueue是Leader-Followr模式的變種,消費者線程處於等待狀態時,總是等待最先到期的元素,而不是長時間的等待。消費者線程盡量把時間花在處理任務上,最小化空等的時間,以提高線程的利用效率。

無論創建那種線程池 必須要調用ThreadPoolExecutor,以上四種都是調用這個實現的

線程池類為 java.util.concurrent.ThreadPoolExecutor,常用構造方法為:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,

long keepAliveTime, TimeUnit unit,

BlockingQueue workQueue,

RejectedExecutionHandler handler)

corePoolSize: 線程池維護線程的最少數量 

maximumPoolSize:線程池維護線程的最大數量 

keepAliveTime: 線程池維護線程所允許的空閑時間 , unit: 線程池維護線程所允許的空閑時間的單位 

workQueue: 線程池所使用的緩沖隊列 

handler: 線程池對拒絕任務的處理策略 --飽和策略

-------------------------------------------------------------------

通用流程:

一個任務通過 execute(Runnable)方法被添加到線程池,任務就是一個 Runnable類型的對象,任務的執行方法就是 Runnable類型對象的run()方法。

當一個任務通過execute(Runnable)方法欲添加到線程池時:

如果此時線程池中的數量小於corePoolSize,即使線程池中的線程都處於空閑狀態,也要創建新的線程來處理被添加的任務。

如果此時線程池中的數量等於 corePoolSize,但是緩沖隊列 workQueue未滿,那麼任務被放入緩沖隊列。

如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量小於maximumPoolSize,建新的線程來處理被添加的任務。

如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量等於maximumPoolSize,那麼通過 handler所指定的策略來處理此任務。

也就是:處理任務的優先順序為:

核心線程corePoolSize、任務隊列workQueue、最大線程maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。 

當線程池中的線程數量大於 corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態的調整池中的線程數。

---------------------------------------------------------------------------------------------

unit可選的參數為java.util.concurrent.TimeUnit中的幾個靜態屬性:

NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue我常用的是:java.util.concurrent. ArrayBlockingQueue

handler有四個選擇:

1、【拋異常】ThreadPoolExecutor.AbortPolicy() 拋出java.util.concurrent.RejectedExecutionException異常

2、【重試】ThreadPoolExecutor.CallerRunsPolicy() 重試添加當前的任務,他會自動重復調用execute()方法

ThreadPoolExecutor.DiscardOldestPolicy()

3、【找個舊的停了】拋棄舊的任務 ThreadPoolExecutor.DiscardPolicy()

4、【不拋異常】拋棄當前的任務

5、當然也可以根據應用場景實現RejectedExecutionHandler介面,自定義 飽和策略 ,如記錄日誌或持久化存儲不能處理的任務。

https://www.cnblogs.com/zhanshi/p/5469948.html

㈢ 面試題系列:並發編程之線程池及隊列

用newCachedThreadPool()方法創建該線程池對象,創建之初裡面一個線程都沒有,當execute方法或submit方法向線程池提交任務時,會自動新建線程;如果線程池中有空餘線程,則不會新建;這種線程池一般最多情況可以容納幾萬個線程,裡面的線程空餘60s會被回收。

適用場景:執行很多短期非同步的小程序。

固定線程數的池子,每個線程的存活時間是無限的,當池子滿了就不再添加線程;若池中線程均在繁忙狀態,新任務會進入阻塞隊列中(無界的阻塞隊列)。

適用場景:執行長期的任務,性能較好。

只有一個線程的線程池,且線程的存活時間是無限的;當線程繁忙時,對於新任務會進入阻塞隊列中(無界的阻塞隊列)。

適用:一個任務一個任務執行的場景。

創建一個固定大小的線程池,池內的線程存活時間無限,線程池支持定時及周期性的任務執行。如果所有線程均處於繁忙狀態,對於新任務會進入 DelayedWorkQueue 隊列。

適用場景:周期性執行任務的場景。

線程池任務執行流程:

ThreadPoolExecutor類實現了ExecutorService介面和Executor介面。

ThreadPoolExecutor 參數:

線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量等於maximumPoolSize,那麼通過 handler所指定的策略來處理此任務。

拋出java.util.concurrent.RejectedExecutionException異常。

用於被拒絕任務的處理程序,它直接在 execute 方法的調用線程中運行被拒絕的任務;如果執行程序已關閉,則會丟棄該任務。

丟棄任務隊列中最舊任務。

丟棄當前將要加入隊列的任務。

DelayQueue 是一個支持延時獲取元素的無界阻塞隊列。隊列使用 PriorityQueue 來實現。隊列中的元素必須實現Delayed介面,在創建元素時可以指定多久才能從隊列中獲取當前元素。只有在延遲期滿時才能從隊列中提取元素。

緩存系統的設計:使用DelayQueue保存緩存元素的有效期,使用一個線程循環查詢DelayQueue,一旦能從DelayQueue中獲取元素時,就表示有緩存到期了。

定時任務調度:使用DelayQueue保存當天要執行的任務和執行時間,一旦從DelayQueue中獲取到任務就開始執行,比如Timer就是使用DelayQueue實現的。

以支持優先順序的PriorityQueue無界隊列作為一個容器,因為元素都必須實現Delayed介面,可以根據元素的過期時間來對元素進行排列,因此,先過期的元素會在隊首,每次從隊列里取出來都是最先要過期的元素。如果延遲隊列中的消息到了延遲時間則可以從中取出消息否則無法取出消息也就無法消費。

CyclicBarrier就是一個柵欄,等待所有線程到達後再執行相關的操作。barrier 在釋放等待線程後可以重用。

CountDownLatch 是計數器, 線程完成一個就記一個, 就像 報數一樣, 只不過是遞減的。

而CyclicBarrier更像一個水閘, 線程執行就像水流, 在水閘處都會堵住, 等到水滿(線程到齊)了, 才開始泄流。

㈣ spring中的線程池

org.springframework.scheling.concurrent.ThreadPoolTaskExecutor 是spring提供的線程池類

拒絕策略:

AbortPolicy:用於被拒絕任務的處理程序,它將拋出RejectedExecutionException

CallerRunsPolicy:用於被拒絕任務的處理程序,它直接在execute方法的調用線程中運行被拒絕的任務。

DiscardOldestPolicy:用於被拒絕任務的處理程序,它放棄最舊的未處理請求,然後重試execute。

DiscardPolicy:用於被拒絕任務的處理程序,默認情況下它將丟棄被拒絕的任務。

執行過程:

如果此時線程池中的數量小於corePoolSize,即使線程池中的線程都處於空閑狀態,也要創建新的線程來處理被添加的任務。

如果此時線程池中的數量等於 corePoolSize,但是緩沖隊列 workQueue未滿,那麼任務被放入緩沖隊列。

如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量小於maxPoolSize,建新的線程來處理被添加的任務。

如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量等於maxPoolSize,那麼通過handler所指定的策略來處理此任務。也就是:處理任務的優先順序為:核心線程corePoolSize、任務隊列workQueue、最大線程 maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。

當線程池中的線程數量大於corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態的調整池中的線程數。

核心線程數設置參考:
CPU密集型:核心線程數 = CPU核數 + 1
IO密集型:核心線程數 = CPU核數 * 2

什麼是CPU密集型?什麼是IO密集型?
https://blog.csdn.net/youanyyou/article/details/78990156
CPU密集型也叫計算密集型,計算密集型任務的特點是要進行大量的計算,消耗CPU資源,這種計算密集型任務雖然也可以用多任務完成,但是任務越多,花在任務切換的時間就越多,CPU執行任務的效率就越低,所以,要最高效地利用CPU,計算密集型任務同時進行的數量應當等於CPU的核心數。
IO密集型,涉及到網路、磁碟IO的任務都是IO密集型任務,這類任務的特點是CPU消耗很少,任務的大部分時間都在等待IO操作完成(因為IO的速度遠遠低於CPU和內存的速度)。對於IO密集型任務,任務越多,CPU效率越高,但也有一個限度。

參考:
https://blog.csdn.net/weixin_43168010/article/details/97613895

https://www.cnblogs.com/redcool/p/6426173.html

https://blog.csdn.net/lifulian318/article/details/109000675

補充:拒絕策略使用場景和其他第三方拒絕策略,參考: https://blog.csdn.net/zj57356498318/article/details/102579980

㈤ 自定義線程池拒絕策略及有界無界隊列

核心線程數:實際運行的線程數

最大線程數:最大可以創建的線程數

(1)ThreadPoolExecutor.AbortPolicy 丟棄任務,並拋出 RejectedExecutionException 異常。

(2)ThreadPoolExecutor.CallerRunsPolicy:該任務被線程池拒絕,由調用 execute方法的線程執行該任務。

(3)ThreadPoolExecutor.DiscardOldestPolicy : 拋棄隊列最前面的任務,然後重新嘗試執行任務。

(4)ThreadPoolExecutor.DiscardPolicy,丟棄任務,不過也不拋出異常。

當線程池的任務緩存隊列已滿並且線程池中的線程數目達到maximumPoolSize,如果還有任務到來就會採取任務拒絕策略。

一個任務通過 execute(Runnable) 方法被添加到線程池,任務就是一個 Runnable 類型的對象,任務的執行方法就是 Runnable 類型對象的 run() 方法。

當一個任務通過 execute(Runnable) 方法欲添加到線程池時,線程池採用的策略如下(即添加任務的策略):

如果此時線程池中的數量小於 corePoolSize ,即使線程池中的線程都處於空閑狀態,也要創建新的線程來處理被添加的任務。

如果此時線程池中的數量等於 corePoolSize ,但是緩沖隊列 workQueue 未滿,那麼任務被放入緩沖隊列。

如果此時線程池中的數量大於 corePoolSize ,緩沖隊列 workQueue 滿,並且線程池中的數量小於maximumPoolSize ,建新的線程來處理被添加的任務。

如果此時線程池中的數量大於 corePoolSize ,緩沖隊列 workQueue 滿,並且線程池中的數量等於maximumPoolSize ,那麼通過 handler 所指定的策略來處理此任務。

任務處理的優先順序(順序)為:

核心線程 corePoolSize 、任務隊列 workQueue 、最大線程 maximumPoolSize ,如果三者都滿了,使用 handler處理被拒絕的任務。當線程池中的線程數量大於 corePoolSize 時,如果某線程空閑時間超過 keepAliveTime ,線程將被終止。這樣,線程池可以動態的調整池中的線程數。

從有界無界上分

常見的有界隊列為

ArrayBlockingQueue 基於數組實現的阻塞隊列

LinkedBlockingQueue 其實也是有界隊列,但是不設置大小時就是無界的。

ArrayBlockingQueue 與 LinkedBlockingQueue 對比一哈

ArrayBlockingQueue 實現簡單,表現穩定,添加和刪除使用同一個鎖,通常性能不如後者

LinkedBlockingQueue 添加和刪除兩把鎖是分開的,所以競爭會小一些

SynchronousQueue 比較奇葩,內部容量為零,適用於元素數量少的場景,尤其特別適合做交換數據用,內部使用 隊列來實現公平性的調度,使用棧來實現非公平的調度,在Java6時替換了原來的鎖邏輯,使用CAS代替了

上面三個隊列他們也是存在共性的

put take 操作都是阻塞的

offer poll 操作不是阻塞的,offer 隊列滿了會返回false不會阻塞,poll 隊列為空時會返回null不會阻塞

補充一點,並不是在所有場景下,非阻塞都是好的,阻塞代表著不佔用CPU,在有些場景也是需要阻塞的,put take 存在必有其存在的必然性

常見的無界隊列

ConcurrentLinkedQueue 無鎖隊列,底層使用CAS操作,通常具有較高吞吐量,但是具有讀性能的不確定性,弱一致性——不存在如ArrayList等集合類的並發修改異常,通俗的說就是遍歷時修改不會拋異常

PriorityBlockingQueue 具有優先順序的阻塞隊列

DelayedQueue 延時隊列,使用場景

緩存:清掉緩存中超時的緩存數據

任務超時處理

補充:內部實現其實是採用帶時間的優先隊列,可重入鎖,優化阻塞通知的線程元素leader

LinkedTransferQueue 簡單的說也是進行線程間數據交換的利器,在SynchronousQueue 中就有所體現,並且並發大神 Doug Lea 對其進行了極致的優化,使用15個對象填充,加上本身4位元組,總共64位元組就可以避免緩存行中的偽共享問題,其實現細節較為復雜,可以說一下大致過程:

比如消費者線程從一個隊列中取元素,發現隊列為空,他就生成一個空元素放入隊列 , 所謂空元素就是數據項欄位為空。然後消費者線程在這個欄位上旅轉等待。這叫保留。直到一個生產者線程意欲向隊例中放入一個元素,這里他發現最前面的元素的數據項欄位為 NULL,他就直接把自已數據填充到這個元素中,即完成了元素的傳送。大體是這個意思,這種方式優美了完成了線程之間的高效協作。參考自 

㈥ 線程池-參數篇:2.隊列

多線程環境中,通過隊列可以很容易實現線程間數據共享,比如經典的「生產者」和「消費者」模型中,通過隊列可以很便利地實現兩者之間的數據共享;同時作為BlockingQueue的使用者,我們不需要關心什麼時候需要阻塞線程,什麼時候需要喚醒線程,因為這一切BlockingQueue的實現者都給一手包辦了。

基於數組的阻塞隊列實現,在ArrayBlockingQueue內部,維護了一個定長數組,以便緩存隊列中的數據對象,另外還保存著兩個整形變數,分別標識著隊列的頭部和尾部在數組中的位置。

ArrayBlockingQueue在生產者放入數據和消費者獲取數據,都是共用同一個鎖對象,由此也意味著兩者無法真正並行運行,而在創建ArrayBlockingQueue時,我們還可以控制對象的內部鎖是否採用公平鎖,默認採用非公平鎖。

按照實現原理來分析,ArrayBlockingQueue完全可以採用分離鎖,從而實現生產者和消費者操作的完全並行運行。

基於鏈表的阻塞隊列,其內部也維持著一個數據緩沖隊列(由一個鏈表構成),當生產者往隊列中放入一個數據時,隊列會從生產者手中獲取數據,並緩存在隊列內部,而生產者立即返回;只有當隊列緩沖區達到最大值緩存容量時(LinkedBlockingQueue可以通過構造函數指定該值),才會阻塞生產者隊列,直到消費者從隊列中消費掉一份數據,生產者線程會被喚醒,反之對於消費者這端的處理也基於同樣的原理。

對於生產者端和消費者端分別採用了獨立的鎖來控制數據同步,這也意味著在高並發的情況下生產者和消費者可以並行地操作隊列中的數據,以此來提高整個隊列的並發性能。

ArrayBlockingQueue和LinkedBlockingQueue間還有一個明顯的不同之處在於,前者在插入或刪除元素時不會產生或銷毀任何額外的對象實例,而後者則會生成一個額外的Node對象。這在長時間內需要高效並發地處理大批量數據的系統中,其對於GC的影響還是存在一定的區別。如果沒有指定其容量大小,LinkedBlockingQueue會默認一個類似無限大小的容量(Integer.MAX_VALUE),這樣的話,如果生產者的速度一旦大於消費者的速度,也許還沒有等到隊列滿阻塞產生,系統內存就有可能已被消耗殆盡了。

ArrayBlockingQueue和LinkedBlockingQueue是兩個最普通也是最常用的阻塞隊列,一般情況下,在處理多線程間的生產者消費者問題,使用這兩個類足以。

DelayQueue中的元素只有當其指定的延遲時間到了,才能夠從隊列中獲取到該元素。DelayQueue是一個沒有大小限制的隊列,因此往隊列中插入數據的操作(生產者)永遠不會被阻塞,而只有獲取數據的操作(消費者)才會被阻塞。

DelayQueue用於放置實現了Delayed介面的對象,其中的對象只能在其到期時才能從隊列中取走。這種隊列是有序的,即隊頭對象的延遲到期時間最長。注意:不能將null元素放置到這種隊列中。

Delayed 是一種混合風格的介面,用來標記那些應該在給定延遲時間之後執行的對象。Delayed擴展了Comparable介面,比較的基準為延時的時間值,Delayed介面的實現類getDelay的返回值應為固定值(final)。DelayQueue內部是使用PriorityQueue實現的。

考慮以下場景:

一種笨笨的辦法就是,使用一個後台線程,遍歷所有對象,挨個檢查。這種笨笨的辦法簡單好用,但是對象數量過多時,可能存在性能問題,檢查間隔時間不好設置,間隔時間過大,影響精確度,多小則存在效率問題。而且做不到按超時的時間順序處理。

這場景,使用DelayQueue最適合了,詳情查看 DelayedQueue學習筆記 ; 精巧好用的DelayQueue

基於優先順序的阻塞隊列(優先順序的判斷通過構造函數傳入的Compator對象來決定),需要注意PriorityBlockingQueue並不會阻塞數據生產者,而只會在沒有可消費的數據時,阻塞數據的消費者。

使用時,若生產者生產數據的速度快於消費者消費數據的速度,隨著長時間的運行,可能會耗盡所有的可用堆內存空間。在實現PriorityBlockingQueue時,內部控制線程同步的鎖採用的是公平鎖。

SynchronousQueue是一個內部只能包含零個元素的隊列。插入元素到隊列的線程被阻塞,直到另一個線程從隊列中獲取元素。同樣,如果線程嘗試獲取元素並且當前沒有線程在插入元素,則該線程將被阻塞,直到有線程將元素插入隊列

聲明一個SynchronousQueue有公平模式和非公平模式,區別如下:

參考: Java多線程-工具篇-BlockingQueue
12. SynchronousQueue

㈦ 線程池創建的4種方式與參數詳解

Executors 是 Executor 的工具類,提供了4種創建不同線程池的方式,來滿足業務的需求。底層是調ThreadPoolExecutor類構造方法。

newFixedThreadPool:創建的是定長的線程池,可以控制線程最大並發數,超出的線程會在線程隊列中等待,使用的是無界隊列,核心線程數和最大線程數一樣,當線程池中的線程沒有任務時候立刻銷毀,使用默認線程工廠。

newSingleThreadExecutor:創建的是單線程化的線程池,只會用唯一一個工作線程執行任務,可以指定按照是否是先入先出,還是優先順序來執行任務。同樣使用無界隊列,核心線程數和最大線程數都是1個,同樣keepAliveTime為0,可選擇是否使用默認線程工廠。

newCachedThreadPool:設定一個可緩存的線程池,當線程池長度超過處理的需要,可以靈活回收空閑線程,如果沒有可以回收的才新建線程。沒有核心線程數,當線程沒有任務60s之後就會回收空閑線程,使用有界隊列。同樣可以選擇是否使用默認線程工廠。

newScheledThreadPool:支持線程定時操作和周期性操作。

Executors工具類創建線程池底層是調ThreadPoolExecutor構造方法。
1、ThreadPoolExecutor4個創建線程池的構造方法:

2、參數詳解
corePoolSize:核心線程數量。當線程數少於corePoolSize的時候,直接創建新的線程,盡管其他線程是空閑的。當線程池中的線程數目達到corePoolSize後,就會把到達的任務放到緩存隊列當中。

maximunPoolSize:線程池最大線程數。只有在緩沖隊列滿了之後才會申請超過核心線程數的線程。當線程數量大於最大線程數且阻塞隊列滿了這時候就會執行一些策略來響應該線程。

workQueue:阻塞隊列。存儲等待執行的任務,會對線程池的運行產生很大的影響。當提交一個新的任務到線程池的時候,線程池會根據當前線程數量來選擇不同的處理方式。

keepAliveTime:允許線程的空閑時間。當超過了核心線程數之外的線程在空閑時間到達之後會被銷毀。

unit:keepAliveTime的時間單位。

threadFactory:線程工廠。用來創建線程,當使用默認的線程工廠創建線程的時候,會使得線程具有相同優先順序,並且設置了守護性,同時也設置線程名稱。

handler:拒絕策略。當workQueue滿了,並且沒有空閑的線程數,即線程達到最大線程數。就會有四種不同策略來處理

待補充。

參考資料
https://www.jianshu.com/p/272e36149e05

㈧ 線程池數量以及隊列長度如何分配

下面我們分析一波,怎麼配置會讓我們系統處理能力更快?

首先我們幾乎可以忽略隊列本身占內存的情況,主要考慮多線程取隊列數據競爭問題以及線程數量

而線程池以及線程數的選用真正線程數的選用主要看壓測,看看處理時間

單一變數原則,我們可以固定我們的線程數量來進行壓測看看,比如說我們固定要創建64個線程,那麼可以有以下幾種線程池分配方式

我們先要找出最優情況,在沒有慢請求的情況下64*1的速度必然是處理速度最快的,然後我們可以進行多種情況壓測,看看誰最接近我們最優情況那就是哪個配置更適合我們。

通常情況下慢查詢比較多可以少隊列,多線程,如果查詢速度非常快,可以偏向於用多隊列單線程,選擇方向即 少競爭,少阻塞,最終配置要看壓測,這玩意很玄,想直接數學計算不太行

㈨ 線程池中的隊列

runnableTaskQueue (任務隊列):用於保存等待執行的任務的阻塞隊列。 可以選擇以下幾個阻塞隊列:

BlockingQueue的幾個注意點

【1】BlockingQueue 可以是限定容量的。它在任意給定時間都可以有一個remainingCapacity,超出此容量,便無法無阻塞地put 附加元素。沒有任何內部容量約束的BlockingQueue 總是報告Integer.MAX_VALUE 的剩餘容量。

【2】BlockingQueue 實現主要用於生產者-使用者隊列,但它另外還支持Collection 介面。

【3】BlockingQueue 實現是線程安全的。

【4】BlockingQueue 實質上不 支持使用任何一種「close」或「shutdown」操作來指示不再添加任何項。

1)ArrayBlockingQueue:規定大小的BlockingQueue,其構造函數必須帶一個int參數來指明其大小.其所含的對象是以FIFO(先入先出)順序排序的.

1:它是有界阻塞隊列。它是數組實現的,是一個典型的「有界緩存區」。數組大小在構造函數指定,而且從此以後不可改變。

2:是它線程安全的,是阻塞的,具體參考BlockingQueue的「注意4」。

3:不接受 null 元素

4:公平性 (fairness)可以在構造函數中指定。如果為true,則按照 FIFO 順序訪問插入或移除時受阻塞線程的隊列;如果為 false,則訪問順序是不確定的。

5:它實現了BlockingQueue介面。關於BlockingQueue,請參照《 BlockingQueue 》

6:此類及其迭代器實現了 Collection 和 Iterator 介面的所有可選 方法。

7:其容量在構造函數中指定。容量不可以自動擴展,也沒提供手動擴展的介面。

8:在JDK5/6中,LinkedBlockingQueue和ArrayBlocingQueue等對象的poll(long timeout, TimeUnit unit)存在內存泄露Leak的對象是AbstractQueuedSynchronizer.Node,

2)LinkedBlockingQueue:大小不定的BlockingQueue,若其構造函數帶一個規定大小的參數,生成的BlockingQueue有大小限制,若不帶大小參數,所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定.其所含的對象是以FIFO(先入先出)順序排序的

並發庫中的 BlockingQueue 是一個比較好玩的類,顧名思義,就是阻塞隊列。該類主要提供了兩個方法put()和take(),前者將一個對象放到隊列中,如果隊列已經滿了,就等待直到有空閑節點;後者從head取一個對象,如果沒有對象,就等待直到有可取的對象。

3)PriorityBlockingQueue:類似於LinkedBlockQueue,但其所含對象的排序不是FIFO,而是依據對象的自然排序順序或者是構造函數的Comparator決定的順序.

1:它是無界阻塞隊列,容量是無限的,它使用與類PriorityQueue相同的順序規則。

2:它是線程安全的,是阻塞的

3:不允許使用 null 元素。

4:對於put(E o)和offer(E o, long timeout, TimeUnit unit),由於該隊列是無界的,所以此方法永遠不會阻塞。因此參數timeout和unit沒意義,會被忽略掉。

5:iterator() 方法中所提供的迭代器並不保證以特定的順序遍歷 PriorityBlockingQueue 的元素。

如果需要有序地遍歷,則應考慮使用 Arrays.sort(pq.toArray())。

6.至於使用和別的BlockingQueue(ArrayBlockingQueue,LinkedBlockingQueue)相似,可以參照它們。7:此類及其迭代器實現了 Collection 和 Iterator 介面的所有可選 方法。

4)SynchronousQueue:特殊的BlockingQueue,對其的操作必須是放和取交替完成的.(每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,)此隊列不允許 null 元素。

SynchronousQueue的定義如下

public classSynchronousQueueextends AbstractQueue implements BlockingQueue , Serializable

從上面可以看出,它實現BlockingQueue,所以是阻塞隊列,從名字看,它又是同步的。

它模擬的功能類似於生活中一手交錢一手交貨這種情形,像那種貨到付款或者先付款後發貨模型不適合使用SynchronousQueue。

首先要知道SynchronousQueue沒有容納元素的能力,即它的isEmpty()方法總是返回true

另外在創建SynchronousQueue時可以傳遞一個boolean參數來指定它是否是訪問它的線程按遵守FIFO順序處理,true表示遵守FIFO。

newCachedThreadPool() 緩存型池子,先查看池中有沒有以前建立的線程,如果有,就reuse.如果沒有,就建一個新的線程加入池中。能reuse的線程,必須是timeout IDLE內的池中線程,預設timeout是60s,超過這個IDLE時長,線程實例將被終止及移出池。緩存型池子通常用於執行一些生存期很短的非同步型任務 。 所用隊列為SynchronousQueue()

newFixedThreadPool() fixedThreadPool與cacheThreadPool差不多,也是能reuse就用,但不能隨時建新的線程 其獨特之處:任意時間點,最多隻能有固定數目的活動線程存在,此時如果有新的線程要建立,只能放在另外的隊列中等待,直到當前的線程中某個線程終止直接被移出池子。和cacheThreadPool不同:fixedThreadPool池線程數固定,但是0秒IDLE(無IDLE)。這也就意味著創建的線程會一直存在。所以fixedThreadPool多數針對一些很穩定很固定的正規並發線程,多用於伺服器。 所用隊列為LinkedBlockingQueue()

newScheledThreadPool() 調度型線程池。這個池子里的線程可以按schele依次delay執行,或周期執行 。0秒IDLE(無IDLE)。 所用隊列為 DelayedWorkQueue()

newSingleThreadExecutor() 單例線程,任意時間池中只能有一個線程 。用的是和cache池和fixed池相同的底層池,但線程數目是1-1,0秒IDLE(無IDLE)。 所用隊列為LinkedBlockingQueue()