《java併發程式設計的藝術》執行緒池

sayWhat_sayHello發表於2018-07-20

好處:
1. 降低資源消耗
2. 提高響應速度
3. 提高執行緒的可管理性

處理流程

提交任務到執行緒池的處理流程:

graph LR
A[提交任務]-->B(核心執行緒池)
B-->C{判斷核心執行緒池是否滿}
C-->|滿了| D{判斷工作佇列是否滿了}
C-->|沒滿| E[建立新的工作執行緒]
D-->|滿了| F{判斷核心執行緒池是否滿了}
D-->|沒滿| G[將任務儲存到佇列裡]
F-->|滿了| H[交給飽和策略處理]
F-->|沒滿| J[建立新執行緒執行工作]

ThreadPoolExecutor執行execute方法的流程和上述相似。(避免獲取全域性鎖)
1. 如果當前執行的執行緒少於corePoolSize,建立新執行緒來執行任務(需要獲取全域性鎖)否則,將任務加入BlockingQueue
2. 如果BlockingQueue滿,建立新的執行緒處理任務
3. 如果建立新執行緒將使當前執行的執行緒超過maximumPoolSize,任務被拒絕,並呼叫RejectedExecutionHandler.rejectedExecution方法

執行緒池建立執行緒時,會將執行緒封裝成工作執行緒Worker,Worker在執行完任務後,迴圈獲取工作佇列裡的任務執行。

執行緒池的使用

建立:

new ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
  • corePoolSize:執行緒池的基本大小
  • maximumPoolSize:執行緒池最大數量
  • keepAliveTime:執行緒活動保持時間。執行緒池工作執行緒空閒後保持存活的時間。
  • unit:執行緒活動保持時間的單位
  • workQueue:任務佇列,用於保持等待執行的任務的阻塞佇列。4種:ArrayBlockingQueue(基於陣列結構的有界阻塞佇列,FIFO),LinkedBlockingQueue(基於連結串列結果的有界阻塞佇列),SynchronousQueue(一個不儲存元素的阻塞佇列。每個插入操作必須等到另一個執行緒呼叫移除操作否則插入操作一直處於阻塞狀態),PriorityBlockingQueue(具有優先順序的無限阻塞佇列).
  • threadFactory:設定執行緒的工廠,可以通過執行緒工廠給每個建立的執行緒設定更有意義的名字。
  • handler:飽和策略,佇列和執行緒滿了,執行緒池就處於飽和狀態。4種處理提交新任務的策略:AbortPolicy(直接拋異常),CallerRunsPolicy(只用呼叫者所線上程執行任務),DiscardOldestPolicy(丟棄佇列裡最近的一個任務並執行當前任務),DiscardPolicy(不處理,直接丟棄)

向執行緒池提交任務,兩個方法execute()和submit()
execute()方法用於提交不需要返回值的任務,無法判斷任務是否被執行緒池執行成功。

threadsPool.execute(new Runnable(){
    @Override
    public void run(){

    });
}

submit()方法用於提交需要返回值的任務。執行緒池會返回一個future型別的物件,通過future的get()獲取返回值,get()方法會阻塞當前執行緒直到任務完成,使用get(long timeout,TimeUnit unit)方法則會阻塞當前執行緒一段時間後立即返回。

Future<?> future = threadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {

            }
        });
        try {
            future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

關閉執行緒池:
呼叫shutdown或shutdownNow方法關閉執行緒池。原理是遍歷執行緒池的工作執行緒,逐個呼叫執行緒的interrupt方法中斷執行緒。
shutdown將執行緒池狀態設定為STOP狀態,然後中斷所有沒有在執行任務的執行緒。
shutdownNow:首先將執行緒池狀態設定為STOP狀態,然後嘗試停止所有正在執行或暫停任務的執行緒並返回等待執行任務的列表。

呼叫上述方法後,isShutDown方法就會返回true。當所有任務都關閉後,呼叫isTerminated方法才會返回true。

配置執行緒池,分析角度:
- 任務的性質:CPU密集型任務(儘可能小的執行緒),IO密集型任務(儘可能多的執行緒),混合型任務
- 任務的優先順序(PriorityBlockingQueue):中,高,低
- 任務的執行時間:長,中,短
- 任務的依賴性(執行緒數設定的越大越好利用CPU):是否依賴其他系統資源,如資料庫連線。

建議使用有界佇列增加系統的穩定性和預警能力。

執行緒池的監控:
- taskCount:執行緒池需要執行的任務數量。
- completedTaskCount:執行緒池在執行過程中已經完成的任務數量,小於或等於taskCount.
- largestPoolSize:執行緒池裡曾經建立過的最大執行緒數量。
- getPoolSize:執行緒池的執行緒數量
- getActiveCount:獲取活動的執行緒數

相關文章