Java線程池詳解_JDK1.8.0_191


Java線程池


線程池的作用

1.重用存在的線程,減少處理多請求時線程創建、銷毀產生的開銷。

2.請求達到時工作線程通常已經存在,請求無需等待,提高系統的響應性。


Executors中線程池的靜態工廠方法

1.newFixedThreadPool

創建一個定長的線程池,每當提交一個任務就創建一個線程,直到達到池的最大長度,這時線程池會保持長度不再變化。

2.newCachedThreadPool

創建一個可緩存的線程池,如果當前線程池的長度超過了處理的需要時,它可以靈活地回收空閑的線程,當需求增加時,它可以靈活添加新的線程。

3.newSingleThreadExecutor

創建一個單線程化的executor,它只創建唯一的工作者線程來執行任務,executor會保證任務依照任務隊列所規定的順序(FIFO、LIFO、優先級)執行。

4.newScheduledThreadPool

創建一個定長的線程池,而且支持定時的以及周期性的任務執行,類似於Timer。


ThreadPoolExecutor類中線程池的構造函數

/**
 * 通過給定的初始化參數創建一個線程池(ThreadPoolExecutor)
 *
 * @param corePoolSize 線程池的核心線程數,核心線程即使空閑也不會被銷毀,
* 除非allowCoreThreadTimeOut被設置
* @param maximumPoolSize 線程池中允許的最大線程數 * @param keepAliveTime 表示當前線程數大於核心線程數時,空閑線程被銷毀前
* 等待新任務到達的最大時間 *
@param unit keepAliveTime參數的時間單位 * @param workQueue 在任務被執行前用來存放的隊列,這個隊列將僅僅存放execute方法提交的Runnable任務 * @param threadFactory executor創建新線程所用的工廠 * @param handler 由於線程數量和隊列容量已滿,執行被阻塞時的拒絕策略 * @throws IllegalArgumentException if one of the following holds:<br> * {@code corePoolSize < 0}<br> * {@code keepAliveTime < 0}<br> * {@code maximumPoolSize <= 0}<br> * {@code maximumPoolSize < corePoolSize} * @throws NullPointerException if {@code workQueue} * or {@code threadFactory} or {@code handler} is null */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }

 線程池的參數

1.核心線程數:即使在空閑時也不會被銷毀的線程數

2.最大線程數:線程池中允許的最大線程數

3.保持存活時間:空閑線程在被銷毀之前等待新任務的時間

4.存活時間單位:等待時間的單位

5.工作隊列:存放待執行任務的隊列

6.線程工廠:新線程創建的工廠

7.拒絕策略:當線程數量和隊列已滿時采取的拒絕策略


工作隊列

工作隊列有多種,但都實現BlockQueue接口

隊列類型 線程池類型 特點
LinkedBlockingQueue

FixedThreadPool

SingleThreadPool

使用的工作隊列

基於鏈表的先進先出隊列
SynchronousQueue CachedThreadPool使用的工作隊列 不保存提交的任務,而是直接創建一個線程來執行新任務
DelayedWorkQueue ScheduledThreadPool使用的工作隊列  

拒絕策略

1.AbortPolicy:直接丟棄任務並拋出RejectedExecutionException異常。

2.CallerRunsPolicy:只要線程池未關閉,該策略直接在調用者線程中,運行當前被丟棄的任務。

3.DiscardOldestPolicy:丟棄隊列中最老的一個任務,也就是即將要執行的任務,並再次嘗試提交當前任務。

4.DiscardPolicy:丟棄任務,不做任何處理。


 

 線程池任務處理策略

線程池的任務處理如下圖所示

 

邏輯較為清晰,其實這是線程池execute()方法的邏輯,下面看一下源碼:

//通過execute向線程池提交任務
public
void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get();
//如果當前線程數未達到核心線程數,則直接創建線程來執行新任務
if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); }
//否則將任務加入阻塞隊列,這里進行雙重檢查,如果線程池已經關閉,則調用reject(),
//如果當前線程池線程數為0,則新建線程
if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); }
//如果加入阻塞隊列失敗,則嘗試新建一個線程,如果失敗了
//則說明線程池關閉了或者線程達到最大線程數,因此調用reject()
else if (!addWorker(command, false)) reject(command); }

線程池提供了兩個方法,用來關閉線程池。

(1)shutdown():不會立即關閉線程池,但也不接受新的任務,等待隊列中所有任務執行完畢后關閉。

(2)shutdownNow():立即終止線程池,並嘗試打斷正在執行的任務,清空工作隊列,返回尚未執行的任務。


線程池的線程數應該如何設置

Nthreads = Ncpu * (1 + w/c)  w為阻塞時間,c為計算時間

IO密集型:w/c>1,因此線程數應該為cpu的數倍,但需要考慮線程所占內存,因此通常將線程數設置為cpu的2倍。

CPU密集型:w/c=0,因此線程數為CPU個數。通常將線程數設置為CPU+1,防止線程由於偶爾出現的原因而暫停。

 

 

 

 


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM