ThreadPoolExecutor裏面4種拒絕策略

ThreadPoolExecutor類實現了ExecutorService接口和Executor接口,可以設置線程池corePoolSize,最大線程池大小,AliveTime,拒絕策略等。常用構造方法:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,

long keepAliveTime, TimeUnit unit,

BlockingQueue workQueue,

RejectedExecutionHandler handler)

corePoolSize: 線程池維護線程的最少數量

maximumPoolSize:線程池維護線程的最大數量

keepAliveTime: 線程池維護線程所允許的空閒時間

unit: 線程池維護線程所允許的空閒時間的單位

workQueue: 線程池所使用的緩衝隊列

handler: 線程池對拒絕任務的處理策略

當一個任務通過execute(Runnable)方法欲添加到線程池時:

l 如果此時線程池中的數量小於corePoolSize,即使線程池中的線程都處於空閒狀態,也要創建新的線程來處理被添加的任務。

2 如果此時線程池中的數量等於 corePoolSize,但是緩衝隊列 workQueue未滿,那麼任務被放入緩衝隊列。

3 如果此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,並且線程池中的數量小於maximumPoolSize,建新的線程來處理被添加的任務。

4 如果此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,並且線程池中的數量等於maximumPoolSize,那麼通過 handler所指定的策略來處理此任務。也就是:處理任務的優先級爲:核心線程corePoolSize、任務隊列workQueue、最大線程maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。

當線程池中的線程數量大於 corePoolSize時,如果某線程空閒時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態的調整池中的線程數。

handler有四個選擇:


拋出java.util.concurrent.RejectedExecutionException異常 ,示例如下:

private static class Worker implements Runnable {

public void run() {

System.out.println(Thread.currentThread().getName() + " is running");

}

}

public static void main(String[] args) {

int corePoolSize = 5;

int maxPoolSize = 10;

long keepAliveTime = 5;

BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(10);

 //拒絕策略1:將拋出 RejectedExecutionException.

RejectedExecutionHandler handler = 

                             new ThreadPoolExecutor.AbortPolicy();

ThreadPoolExecutor executor = new ThreadPoolExecutor

(corePoolSize, maxPoolSize, 

keepAliveTime, TimeUnit.SECONDS, 

queue, handler);

for(int i=0; i<100; i++) {

executor.execute(new Worker());

}

executor.shutdown();

}

運行結果如下:

pool-1-thread-2 is running

pool-1-thread-3 is running

Exception in thread "main" java.util.concurrent.RejectedExecutionException

pool-1-thread-1 is running

pool-1-thread-7 is running

pool-1-thread-6 is running

pool-1-thread-4 is running

pool-1-thread-9 is running

pool-1-thread-8 is running

pool-1-thread-5 is running

at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1760)

at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:767)

at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:658)

at concurrent.ThreadPoolDemo.main(ThreadPoolDemo.java:33)

pool-1-thread-10 is running

處理源碼如下:

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

           throw new RejectedExecutionException();

       }

策略2:ThreadPoolExecutor.CallerRunsPolicy
用於被拒絕任務的處理程序,它直接在 execute 方法的調用線程中運行被拒絕的任務;如果執行程序已關閉,則會丟棄該任務。如下:

RejectedExecutionHandler handler = 

new ThreadPoolExecutor.CallerRunsPolicy();

運行如下:

pool-1-thread-7 is running

pool-1-thread-7 is running

pool-1-thread-7 is running

pool-1-thread-7 is running

pool-1-thread-7 is running

pool-1-thread-7 is running

pool-1-thread-2 is running

pool-1-thread-3 is running

pool-1-thread-1 is running

pool-1-thread-8 is running

main is running

main is running

main is running

pool-1-thread-4 is running

pool-1-thread-7 is running

pool-1-thread-7 is running

pool-1-thread-7 is running

處理源碼如下:

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

           if (!e.isShutdown()) {

               r.run();

           }

       }

策略3:

RejectedExecutionHandler handler = 

new ThreadPoolExecutor.DiscardOldestPolicy();

這樣運行結果就不會有100個線程全部被執行。處理源碼如下:

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

            if (!e.isShutdown()) {

                e.getQueue().poll();

                e.execute(r);

            }

        }

策略4:ThreadPoolExecutor.DiscardPolicy
用於被拒絕任務的處理程序,默認情況下它將丟棄被拒絕的任務。

運行結果也不會全部執行100個線程。

源碼如下,實際就是對線程不執行操作:

public static class DiscardPolicy implements RejectedExecutionHandler {

     /**

      * Creates a <tt>DiscardPolicy</tt>.

      */

     public DiscardPolicy() { }

 

     /**

      * Does nothing, which has the effect of discarding task r.

      * @param r the runnable task requested to be executed

      * @param e the executor attempting to execute this task

      */

     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

     }

 }

這四種策略是獨立無關的,是對任務拒絕處理的四中表現形式。最簡單的方式就是直接丟棄任務。但是卻有兩種方式,到底是該丟棄哪一個任務,比如可以丟棄當前將要加入隊列的任務本身(DiscardPolicy)或者丟棄任務隊列中最舊任務(DiscardOldestPolicy)。丟棄最舊任務也不是簡單的丟棄最舊的任務,而是有一些額外的處理。除了丟棄任務還可以直接拋出一個異常(RejectedExecutionException),這是比較簡單的方式。拋出異常的方式(AbortPolicy)儘管實現方式比較簡單,但是由於拋出一個RuntimeException,因此會中斷調用者的處理過程。除了拋出異常以外還可以不進入線程池執行,在這種方式(CallerRunsPolicy)中任務將有調用者線程去執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章