任務拒絕策略

在沒有分析線程池原理以前先來分析下爲何有任務拒絕的狀況發生。html

這裏先假設一個前提:線程池有一個任務隊列,用於緩存全部待處理的任務,正在處理的任務將從任務隊列中移除。所以在任務隊列長度有限的狀況下就會出現新任務的拒絕處理問題,須要有一種策略來處理應該加入任務隊列卻由於隊列已滿沒法加入的狀況。另外在線程池關閉的時候也須要對任務加入隊列操做進行額外的協調處理。java

RejectedExecutionHandler提供了四種方式來處理任務拒絕策略緩存

一、直接丟棄(DiscardPolicy)ide

二、丟棄隊列中最老的任務(DiscardOldestPolicy)。.net

三、拋異常(AbortPolicy)線程

四、將任務分給調用線程來執行(CallerRunsPolicy)。orm

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

下面來看下這幾種拒絕策略的例子。blog

使用直接丟棄任務自己的拒絕策略:DiscardPolicy
   隊列

[Java] 純文本查看 複製代碼

?

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

import java.text.SimpleDateFormat;

 

    import java.util.Date;

 

    import java.util.concurrent.ArrayBlockingQueue;

 

    import java.util.concurrent.BlockingQueue;

 

    import java.util.concurrent.ThreadPoolExecutor;

 

    import java.util.concurrent.TimeUnit;

 

 

 

    public class ExecutorDemo {

 

 

 

        private static  SimpleDateFormat sdf  = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

 

        public static void main(String[] args) {

 

            int corePoolSize = 1;

 

            int maximumPoolSize = 1;

 

            BlockingQueue queue = new  ArrayBlockingQueue<Runnable>(1);

 

            ThreadPoolExecutor pool = new ThreadPoolExecutor(corePoolSize,  maximumPoolSize,

 

                    0, TimeUnit.SECONDS, queue ) ;

 

            pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy ());

 

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

 

                final int index = i;

 

                pool.submit(new Runnable(){

 

 

 

                    @Override

 

                    public void run() {

 

                        log(Thread.currentThread().getName()+"begin run task :"+index);

 

                        try {

 

                            Thread.sleep(1000);

 

                        } catch (InterruptedException e) {

 

                            e.printStackTrace();

 

                        }

 

                        log(Thread.currentThread().getName()+" finish run  task :"+index);

 

                    }

 

 

 

                });

 

            }

 

 

 

            log("main thread before sleep!!!");

 

            try {

 

                Thread.sleep(4000);

 

            } catch (InterruptedException e) {

 

                e.printStackTrace();

 

            }

 

            log("before shutdown()");

 

 

 

            pool.shutdown();

 

 

 

            log("after shutdown(),pool.isTerminated=" + pool.isTerminated());

 

            try {

 

                pool.awaitTermination(1000L, TimeUnit.SECONDS);

 

            } catch (InterruptedException e) {

 

                e.printStackTrace();

 

            }

 

            log("now,pool.isTerminated=" + pool.isTerminated());

 

        }

 

 

 

        protected static void log(String string) {

 

            System.out.println(sdf.format(new Date())+"  "+string);

 

        }

 

 

 

    }

運行結果:

    2016-08-04 22:29:21  main thread before sleep!!!
    2016-08-04 22:29:21  pool-1-thread-1begin run task :0
    2016-08-04 22:29:22  pool-1-thread-1 finish run  task :0
    2016-08-04 22:29:22  pool-1-thread-1begin run task :1
    2016-08-04 22:29:23  pool-1-thread-1 finish run  task :1
    2016-08-04 22:29:25  before shutdown()
    2016-08-04 22:29:25  after shutdown(),pool.isTerminated=false
    2016-08-04 22:29:25  now,pool.isTerminated=true
從結果能夠看出,只有task0和task1兩個任務被執行了。

爲何只有task0和task1兩個任務被執行了呢?

過程是這樣的:因爲咱們的任務隊列的容量爲1.當task0正在執行的時候,task1被提交到了隊列中可是尚未執行,受隊列容量的限制,submit提交的task2~task9就都被直接拋棄了。所以就只有task0和task1被執行了。

使用丟棄任務隊列中比較久的任務的拒絕策略:DiscardOldestPolicy
若是將拒絕策略改成:DiscardOldestPolicy(丟棄隊列中比較久的任務)

運行結果爲:

    2016-08-04 22:31:58  pool-1-thread-1begin run task :0
    2016-08-04 22:31:58  main thread before sleep!!!
    2016-08-04 22:31:59  pool-1-thread-1 finish run  task :0
    2016-08-04 22:31:59  pool-1-thread-1begin run task :9
    2016-08-04 22:32:00  pool-1-thread-1 finish run  task :9
    2016-08-04 22:32:02  before shutdown()
    2016-08-04 22:32:02  after shutdown(),pool.isTerminated=false
    2016-08-04 22:32:02  now,pool.isTerminated=true
從結果能夠看出,只有task0和task9被執行了。

使用將任務將由調用者線程去執行的拒絕策略:CallerRunsPolicy
若是將拒絕策略改成:CallerRunsPolicy(即不用線程池中的線程執行,而是交給調用方來執行)

運行結果爲:

    2016-08-04 22:33:07  mainbegin run task :2
    2016-08-04 22:33:07  pool-1-thread-1begin run task :0
    2016-08-04 22:33:08  main finish run  task :2
    2016-08-04 22:33:08  mainbegin run task :3
    2016-08-04 22:33:08  pool-1-thread-1 finish run  task :0
    2016-08-04 22:33:08  pool-1-thread-1begin run task :1
    2016-08-04 22:33:09  pool-1-thread-1 finish run  task :1
    2016-08-04 22:33:09  main finish run  task :3
    2016-08-04 22:33:09  mainbegin run task :5
    2016-08-04 22:33:09  pool-1-thread-1begin run task :4
    2016-08-04 22:33:10  main finish run  task :5
    2016-08-04 22:33:10  mainbegin run task :7
    2016-08-04 22:33:10  pool-1-thread-1 finish run  task :4
    2016-08-04 22:33:10  pool-1-thread-1begin run task :6
    2016-08-04 22:33:11  main finish run  task :7
    2016-08-04 22:33:11  mainbegin run task :9
    2016-08-04 22:33:11  pool-1-thread-1 finish run  task :6
    2016-08-04 22:33:11  pool-1-thread-1begin run task :8
    2016-08-04 22:33:12  main finish run  task :9
    2016-08-04 22:33:12  main thread before sleep!!!
    2016-08-04 22:33:12  pool-1-thread-1 finish run  task :8
    2016-08-04 22:33:16  before shutdown()
    2016-08-04 22:33:16  after shutdown(),pool.isTerminated=false
    2016-08-04 22:33:16  now,pool.isTerminated=true

從結果能夠看出,沒有任務被拋棄,而是將由的任務分配到main線程中執行了。

小結
關於線程池的任務拒絕策略,咱們要理解並記住,有以下的四種:

一、直接丟棄(DiscardPolicy)

二、丟棄隊列中最老的任務(DiscardOldestPolicy)。

三、拋異常

四、將任務分給調用線程來執行。

參考資料
一、http://www.blogjava.net/xylz/...

相關文章
相關標籤/搜索