java-執行緒池(一)

南小瓜發表於2018-12-20

一、為什麼使用執行緒池

  1. 重用執行緒池中的使用,減少建立線和銷燬程的的資源消耗和提高效能。
  2. 可以對執行緒進行管理與維護

二、執行緒池的建立

  執行緒池的建立可以使用Executors類中的方法建立,可以參考常用的四種執行緒池的建立,下面來看J.U.C包下的ThreadPoolExecutor,此類主要有以下構造方法:

/**第一種建立方式*/
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
/**第二章建立方式*/
 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
/**第三種建立方式*/
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
/**第四種建立方式*/
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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

corePoolSize:核心執行緒池的大小,執行緒池建立完成之後,執行緒池中預設沒有任何執行緒。只有在有任務到達時才會建立一個執行緒去執行,直到corePoolSize。

maximumPoolSize:執行緒池中允許最大的執行緒數。

keepAliveTime:空閒執行緒等待新任務的最大存活時間。

unit:keepAliveTime的時間單位,比如TimeUnit.MILLISECONDS;TimeUnit.SECONDS; TimeUnit.MINUTES; TimeUnit.HOURS;

workQueue:阻塞佇列,當執行緒池中的執行緒大於corePoolSize時,新建的任務將會進入阻塞佇列等待執行,可以檢視常用的阻塞佇列

threadFactory:建立執行緒的工廠

handler:拒絕任務的處理策略。

拒絕策略:

  1. AbortPolicy:直接丟棄任務並丟擲RejectedExecutionException。
  2. CallerRunsPolicy:只要執行緒池未關閉,就會執行呼叫者執行緒中丟棄的任務,這樣會降低執行緒的效能。
  3. DiscardOldestPolicy:丟棄任務佇列中時間最長的任務然後嘗試提交當前的任務。
  4. DiscardPolicy:丟棄任務,不做任何處理。

執行緒池處理任務的規則:

  1. 當前執行緒池中執行緒的數目<corePoolSize,則每來一個任務,就會建立一個執行緒來執行
  2. 當前執行緒池中執行緒的數目>=corePoolSize,當有任務時,則會嘗試新增到阻塞佇列中,若新增成功,則會等待空閒執行緒來將其執行,若新增失敗(一般是阻塞佇列已滿),則會建立新的執行緒去執行,當然前提是不能maximumPoolSize的數量。
  3. 若當前執行緒池中的執行緒數量>maximumPoolSize,則執行任務拒絕策略處理
  4. 當前執行緒池中的執行緒數量?corePoolSize時,若某個空閒執行緒超過keepAliveTime時間,則會被丟棄,直到執行緒數量小於corePoolSize。一般情況下,核心執行緒不會被丟棄。

執行緒池中任務到達的執行流程:

執行緒池中的狀態:

  • RUNNING:接收新的任務,執行任務佇列中的任務。
  • SHUTDOWN:不接收新任務,但是執行任務佇列中的任務。
  • STOP:不接收新任務,也不執行任務佇列中的任務,並打斷正在執行的任務。
  • TIDYING:終止所有的任務,工作執行緒的數量為0,並且會執行terminated()回撥函式。
  • TERMINATED:terminated()方法已執行完畢。

狀態轉換:

RUNNING -> SHUTDOWN: 在呼叫shutDown()方法時。

(RUNNING or SHUTDOWN) -> STOP:在呼叫shutDownNow()方法時。

SHUTDOWN -> TIDYING:執行緒池和阻塞佇列都為空。

STOP -> TIDYING :執行緒池為空。

TIDYING -> TERMINATED :terminated()方法執行完畢時。

相關文章