線程複用:線程池
爲了避免系統頻繁地創建和銷燬線程,我們可以讓創建的線程進行復用。線程池中,總有幾個活躍線程。當你需要使用線程時,可以從池中隨便獲取一個空閒線程,當工作完成時,線程不會關閉而是退回池中。
JDK 提供的線程池工廠方法
newFixedThreadPool
返回固定線程數量的線程池。
當有一個新的任務提交時,線程池若有空閒線程,則立即執行。若沒有,則新的任務會被暫存到一個任務隊列中,待線程空閒時,便處理在任務隊列中的任務。
newSingleThreadExecutor
返回只有一個線程的線程池。
若多餘一個任務被提及,則保存到任務隊列中,線程空閒時按照先入先出的順序執行任務。
newCachedThreadPool
返回一個可根據實際情況調整線程數量的線程池。
線程池的線程數量不確定,但若有空閒線程可以複用,則會有限使用可複用的線程。若所有線程均在工作,又有新任務提交,則創建新的線程處理任務。當所有線程在任務執行完之後,將返回線程池進行復用。
newSingleThreadScheduledExecutor
返回一個
ScheduledExecutorService
對象,線程池大小爲1。ScheduledExecutorService
接口在ExecutorService
接口之上擴展了給定時間執行某任務的功能。newScheduledThreadPool
返回指定線程數量的
ScheduledExecutorService
對象。
線程池的內部實現
JDK 提供的線程池工廠方法實質就是
ThreadPoolExecutor
的不同參數的不同實現public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize
: 指定線程池中的線程數量。maximumPoolSize
:指定線程池中的最大線程數量。keepAliveTime
:超過corePoolSize的空閒線程,在多長時間內,會被銷燬。unit
:keepAliveTime的單位。workQueue
:提交但未執行的任務隊列。直接提交的隊列
該功能由
SynchronousQueue
對象提供,提交的任務不會被保存,而是直接提交給線程執行,如果沒有空閒的線程,則嘗試創建新的線程,如果已達到最大值則執行拒絕策略。有界的任務隊列
由
ArrayblockingQueue
實現,ArrayblockingQueue
的構造函數需要帶一個容量參數(隊列最大容量)。當有新的任務時,如果線程池實際線程數小於corePoolSize
,則優先創新新的線程,如果大於corePoolSize
,則將任務加入等待隊列。若等待隊列已滿,則在總線程數不大於
maximumPoolSize
的前提下創建新的線程執行任務,否則則執行拒絕策略。因爲需要等待隊列滿纔會創建超出corePoolSize
的線程,所以除非系統特別繁忙,否則核心線程數一般維持在corePoolSize
。無界的任務隊列
由
LinkedBlockingQueue
實現,和有界的任務隊列類似,只是等待隊列會一直擴張,如果任務的創建速度一直高於處理速度,則無界隊列會一直增長,直至耗盡內存。優先任務隊列
由
PriorityBlockingQueue
實現,是一個特殊的無界隊列,會按照任務自身的優先級順序先後執行。
threadFactory
:線程工廠,用於創建線程,一般默認。handler
:拒絕策略。當任務太多時如何拒絕任務。AbortPolicy 策略
直接拋出異常,阻止系統正常工作。
CallerRunsPolicy 策略
只要線程池未關閉,該策略直接在調用者線程中,運行當前被丟棄的任務。這樣做不會真的丟棄任務,但是任務提交的線程性能可能會急劇下降。
DiscardPolicy 策略
丟棄最老的一個請求(即將被執行的下一個任務),並嘗試再次提交當前任務。
DiscardOldestPolicy 策略
直接丟棄無法處理的任務,不做任何處理。
線程池的數量
Ncpu = CPU數量
Ucup = CPU的使用率
W/C = 等待時間與計算時間的比率
最優池:
Nthreads=Ncpu*Ncpu*(1+W/C)