线程池学习之线程池任务拒绝策略

    xiaoxiao2022-07-02  122

    在上面的一篇文章中讲到了线程池的执行流程,使用起来很简单。对于线程池的任务拒绝策略没有过多的介绍,本文主要介绍线程的四种拒绝策略。

    RejectedExecutionHandler提供了多种方式来处理任务拒绝策略

    通过观察源码可知:所有的拒绝策略他们都实现了RejectedExecutionHandler

    1、直接丢弃(DiscardPolicy)

    2、丢弃队列中最老的任务(DiscardOldestPolicy)。

    3、抛异常(AbortPolicy)

    4、将任务分给调用线程来执行(CallerRunsPolicy)。

    运行一段代码,通过观察线程池里工作的线程池数,来查看线程池的工作状况

    代码如下:

    package juc.threadpool; /** * @Description * @Author DJZ-WWS * @Date 2019/5/22 10:12 */ 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); } }

    简单的说明一下这里线程池的参数的配置:

    corePoolSize我设置成了1,maxiPoolSize最大线程数设置成了 1,阻塞队列设置成了1,也就是说线程池最大的工作线程数不会超过两个,空闲时间设置成了0意味着线程一旦非核心工作线程停止了工作,并且没有任务的时候,那个线程就会立即关闭。线程池里面只剩下一个一个核心线程在工作。

    结果简单分析:

    可以看一下程序运行的结果:

    我们配置的拒绝策略是 DiscardPolicy,源码如下:

    我们可以看到这里面什么也没做,来了任务也不会将任务放到工作队列里。所以被执行的只有0,1线程,其他线程并没有在队列里,也不会被消费。

    将上面代码改成另一个策略

    这个策略意味着线程池任务过多的时候会报异常,运行结果如下:

    Exception in thread "main" 2019-05-23 09:20:57 pool-1-thread-1begin run task :0 java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@5680a178 rejected from java.util.concurrent.ThreadPoolExecutor@5fdef03a[Running, pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379) at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112) at juc.threadpool.ExecutorDemo.main(ExecutorDemo.java:27) 2019-05-23 09:20:58 pool-1-thread-1 finish run task :0 2019-05-23 09:20:58 pool-1-thread-1begin run task :1 2019-05-23 09:20:59 pool-1-thread-1 finish run task :1

    工作线程还是0,1其他任务报异常了。

    配置另一种任务CallerRunPolicy,

    结果如下

    这个拒绝策略的源码如下:

    这个策略显然不想放弃执行任务。那么就用当前的Executor进行执行。不过,这样也有弊端,那就是阻塞当前Executor线程,造成该线程池无法调度任务。

    配置另一种策略: DiscardOldestPolicy

    结果如下

    源码如下:

    我们可以看出这个类通过线程池获取到这个线程池的队列,然后调用poll方法将队列头部的任务拉黑。因为队列中最先进去的任务在队列头部。所以这个实现策略是将最老的任务拒绝掉。由于9号线程是最新的一个线程,其他线程都是在9号之前,所有9号和0号被执行了。

    以上就是jdk提供的四种拒绝策略。

    学习参考:https://blog.csdn.net/u010412719/article/details/52132613

                      https://cloud.tencent.com/developer/news/305388

    最新回复(0)