RejectedExecutionException抛出的原因

场景描述

当一个真实场景是Executor提交所有任务进行计算,然后接着调用shutdown方法,最后调用awaitTermination方法等待所有任务计算结束。偶尔会出现RejectedExecutionException异常。

什么情况下会抛出此异常呢

  1. 当调用shutdown方法正常关闭后,还向线程池提交任务。
  2. 当创建的线程大于线程池最大线程数+阻塞队列的容量的总和

代码测试模拟抛出异常的情况

情况一

1
2
3
4
5
6
7
8
public static void firstTest(){
ThreadPoolExecutor poolExecutor =
new ThreadPoolExecutor(2,3,Long.MAX_VALUE, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(1));
poolExecutor.shutdown();
poolExecutor.submit(() -> {
System.out.println("first");
});
}

情况二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void secondTest() throws InterruptedException{
//创建一个线程数为3的线程池,以及容量为1的阻塞队列
ThreadPoolExecutor poolExecutor =
new ThreadPoolExecutor(2,3,Long.MAX_VALUE, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(1));
//创建5个线程,满足大于线程池最大线程量+阻塞队列容量之和
for( int i = 5 ; i-- > 0; ) {
poolExecutor.submit(()->{
System.out.println("first:" + Thread.currentThread().getName());
try {
//为了延迟线程完成,防止完成以后变成空闲线程被另外一个任务所用
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
});
}
}

处理机制

可以在初始完线程池以后,通过setRejectedExecutionHandler设定抛出异常以后如何处理。情况二的处理属于饱和策略中。其中JDK提供了几种不同的RejectedExcutionHandler实现,每种包含有不同的饱和策略:AbortPolicyCallerRunsPolicyDiscardPolicyDiscartOldestPolicyAbortPolicyz中止策略也是默认的饱和策略,会抛出未检查的RejectedExecutionException,根据需求编写自己的处理代码。CallerRunsPolicy调用者运行策略,不会抛出异常而是将任务回退给调用者,然后会在另一个调用了execute线程中执行该任务。DiscardPolicy表示会抛弃该任务。DiscartOldestPolicy则会抛弃最旧的线程(也就是最先执行的线程)。


评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×