1. 程式人生 > >執行緒池的原理及使用

執行緒池的原理及使用

一. 執行緒池的優點
1:降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗。

2:提高響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。

3:提高執行緒的可管理性。執行緒是稀缺資源,如果無限制地建立,不僅會消耗系統資源,
還會降低系統的穩定性,使用執行緒池可以進行統一分配、調優和監控。但是,要做到合理利用
執行緒池,必須對其實現原理了如指掌。

二. 執行緒池的實現
* ThreadPoolExecutor 是實現執行緒池非常核心的一個類
ThreadPoolExecutor ——>繼承了 AbstractExecutorService ——實現了 ExecutorService ——>繼承了 Executor介面
注:Executor是一個頂層介面,在它裡面只聲明瞭一個方法execute(Runnable),返回值為void,引數為Runnable型別,從字面意思可以理解,就是用來執行傳進去的任務的;



public interface Executor {
void execute(Runnable command);
}

* 在ThreadPoolExecutor類中有幾個非常重要的方法:

execute()
submit()
shutdown()
shutdownNow()

1.submit()方法是在ExecutorService中宣告的方法,在AbstractExecutorService就已經有了具體的實現,在ThreadPoolExecutor中並沒有對其進行重寫,這個方法也是用來向執行緒池提交任務的,但是它和execute()方法不同,它能夠返回任務執行的結果,去看submit()方法的實現,會發現它實際上還是呼叫的execute()方法。
2.shutdown():不會立即終止執行緒池,而是要等所有任務快取佇列中的任務都執行完後才終止,但再也不會接受新的任務
3.shutdownNow():立即終止執行緒池,並嘗試打斷正在執行的任務,並且清空任務快取佇列,返回尚未執行的任務

public class ThreadPoolExecutor extends AbstractExecutorService {
    .....
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue);

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

引數解釋:
* corePoolSize:核心執行緒數量,沒有達到次數量執行緒會不斷建立新的執行緒,個人理解就是執行緒池中正常適合容納的執行緒的數量。

  • maximumPoolSize:執行緒池最多可以容納的執行緒數量,超過這個會觸發飽和策略(RejectedExecutionHandler)

  • keepAliveTime:表示執行緒沒有任務執行時最多保持多久時間會終止。注意:預設情況下,只有當執行緒池中的執行緒數大於corePoolSize時,keepAliveTime才會起作用,直到執行緒池中的執行緒數不大於corePoolSize,即當執行緒池中的執行緒數大於corePoolSize時,如果一個執行緒空閒的時間達到keepAliveTime,則會終止,直到執行緒池中的執行緒數不超過corePoolSize。

  • TimeUnit:keepAliveTime的單位。
    列舉型別:

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小時
TimeUnit.MINUTES;           //分鐘
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //納秒
  • BlockingQueue: 阻塞佇列 這裡大致寫一下,詳細請自己查詢
ArrayBlockingQueue;  //陣列型別  有界,必須規定佇列大小
LinkedBlockingQueue; //連結串列型別,預設Integer.MAX_VALUE
SynchronousQueue;   //一個不儲存元素的阻塞佇列

三. 執行緒的具體使用
程式碼:

public class Task extends Thread{
    private int num;

    public Task(int num) {
        this.num = num;
    }

    @Override
    public void run() {
        System.out.println("正在執行任務:" + num);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println("結束任務:" + num);
    }
}
public class ThreadPool {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
                10, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(5));
        for(int i=0;i<15;i++){
            Task myTask = new Task(i);
            executor.execute(myTask);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("執行緒池中執行緒數目:"+executor.getPoolSize()+",佇列中等待執行的任務數目:"+
                    executor.getQueue().size()+",已執行完別的任務數目:"+executor.getCompletedTaskCount());
        }
        executor.shutdown();
    }
}

通過對任務時間,執行緒的keepAliveTime的調整,觀察執行緒池的狀態。具體如下:

1.線上程的數量沒有達到corePoolSize時,會不斷建立新的執行緒處理任務。

2.達到corePoolSize時會有兩種情況,如果keepAliveTime很小,有執行緒在這個時候是空閒的,就會利用空閒執行緒處理任務,否則就讓任務進入阻塞佇列。

3.阻塞佇列滿時,會接著建立執行緒處理任務,直到到達maximumPoolSize,觸發飽和策略。

四. 飽和策略
RejectedExecutionHandler(飽和策略):

ThreadPoolExecutor.AbortPolicy:丟棄任務並丟擲RejectedExecutionException異常。 
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不丟擲異常。 
ThreadPoolExecutor.DiscardOldestPolicy:丟棄佇列最前面的任務,然後重新嘗試執行任務(重複此過程)
ThreadPoolExecutor.CallerRunsPolicy:由呼叫執行緒處理該任務