任务拒绝策略

在没有分析线程池原理以前先来分析下为何有任务拒绝的状况发生。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/...

相关文章
相关标签/搜索