Java线程池--拒绝策略RejectedExecutionHandler
当线程池的任务缓存队列已满并且线程池中的线程数⽬达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
当线程池的任务缓存队列已满并且线程池中的线程数⽬达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前⾯的任务,然后重新尝试执⾏任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调⽤线程处理该任务
当Executor已经关闭(即执⾏了executorService.shutdown()⽅法后),并且Executor将有限边界⽤于最⼤线程和⼯作队列容量,且已经饱和时,在⽅法execute()中提交的新任务将被拒绝.
在以上述情况下,execute ⽅法将调⽤其 RejectedExecutionHandler 的
线程池默认会采⽤的是defaultHandler策略。⾸先看defaultHandler的定义:
private static final RejectedExecutionHandler defaultHandler =new AbortPolicy();// 使⽤默认的拒绝策略
//丢弃任务并抛出RejectedExecutionException异常。
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy(){}
// 抛出异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e){
throw new RejectedExecutionException("Task "+ r.toString()+" rejected from "+  e.toString());
}
}
如下是⼀个测试任务的例⼦,下⾯编写4个测试⽤例来测试。
class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name){
this.name = name;
}
@Override
public void run(){
try{
System.out.println(this.name +" is running.");
Thread.sleep(100);
}catch(Exception e){
e.printStackTrace();
}
}
}
看⼀下其他拒绝策略的具体实现。
1.DiscardPolicy ⽰例(也是丢弃任务,但是不抛出异常。)
public class DiscardPolicyDemo {
private static final int THREADS_SIZE =1;
private static final int CAPACITY =1;
public static void main(String[] args)throws Exception {
// 创建线程池。线程池的"最⼤池⼤⼩"和"核⼼池⼤⼩"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。
ThreadPoolExecutor pool =new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE,0, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnabl e>(CAPACITY));
// 设置线程池的拒绝策略为"丢弃"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
// 新建10个任务,并将它们添加到线程池中。
for(int i =0; i <10; i++){
Runnable myrun =new MyRunnable("task-"+i);
java线程池创建的四种
}
// 关闭线程池
pool.shutdown();
}
}
线程池pool的”最⼤池⼤⼩”和”核⼼池⼤⼩”都为1(THREADS_SIZE),这意味着”线程池能同时运⾏的任务数量最⼤只能是1”。
线程池pool的阻塞队列是ArrayBlockingQueue,ArrayBlockingQueue是⼀个有界的阻塞队列,ArrayBlockingQueue的容量为1。这也意味着线程池的阻塞队列只能有⼀个线程池阻塞等待。   
根据”“中分析的execute()代码可知:线程池中共运⾏了2个任务。第1个任务直接放到Worker中,通过线程去执⾏;第2个任务放到阻塞队列中等待。其他的任务都被丢弃了!
2.DiscardOldestPolicy ⽰例(丢弃队列最前⾯的任务,然后重新尝试执⾏任务(重复此过程))
public class DiscardOldestPolicyDemo {
private static final int THREADS_SIZE =1;
private static final int CAPACITY =1;
public static void main(String[] args)throws Exception {
// 创建线程池。线程池的"最⼤池⼤⼩"和"核⼼池⼤⼩"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。
ThreadPoolExecutor pool =new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE,0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY));
// 设置线程池的拒绝策略为"DiscardOldestPolicy"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
// 新建10个任务,并将它们添加到线程池中。
for(int i =0; i <10; i++){
Runnable myrun =new MyRunnable("task-"+i);
}
// 关闭线程池
pool.shutdown();
}
}
运⾏结果:
task-0 is running.
task-9 is running.
将”线程池的拒绝策略”由DiscardPolicy修改为DiscardOldestPolicy之后,当有任务添加到线程池被拒绝时,线程池会丢弃阻塞队列中末尾的任务,然后将被拒绝的任务添加到末尾。
3.AbortPolicy ⽰例(丢弃任务并抛出RejectedExecutionException异常。)
public class AbortPolicyDemo {
private static final int THREADS_SIZE =1;
private static final int CAPACITY =1;
public static void main(String[] args)throws Exception {
// 创建线程池。线程池的"最⼤池⼤⼩"和"核⼼池⼤⼩"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。
ThreadPoolExecutor pool =new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE,0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY));
// 设置线程池的拒绝策略为"抛出异常"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
try{
// 新建10个任务,并将它们添加到线程池中。
for(int i =0; i <10; i++){
Runnable myrun =new MyRunnable("task-"+i);
}
}catch(RejectedExecutionException e){
e.printStackTrace();
// 关闭线程池
pool.shutdown();
}
}
}
(某⼀次)运⾏结果:
urrent.RejectedExecutionException
at urrent.jectedExecution(ThreadPoolExecutor.java:1774)
at ject(ThreadPoolExecutor.java:768)
at ute(ThreadPoolExecutor.java:656)
at AbortPolicyDemo.main(AbortPolicyDemo.java:27)
task-0 is running.
task-1 is running.
将”线程池的拒绝策略”由DiscardPolicy修改为AbortPolicy之后,当有任务添加到线程池被拒绝时,会抛出
RejectedExecutionException。
4.CallerRunsPolicy ⽰例(由调⽤线程处理该任务)
public class CallerRunsPolicyDemo {
private static final int THREADS_SIZE =1;
private static final int CAPACITY =1;
public static void main(String[] args)throws Exception {
// 创建线程池。线程池的"最⼤池⼤⼩"和"核⼼池⼤⼩"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。
ThreadPoolExecutor pool =new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE,0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY));
// 设置线程池的拒绝策略为"CallerRunsPolicy"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 新建10个任务,并将它们添加到线程池中。
for(int i =0; i <10; i++){
Runnable myrun =new MyRunnable("task-"+i);
}
// 关闭线程池
pool.shutdown();
}
}
(某⼀次)运⾏结果:
task-2 is running.
task-3 is running.
task-4 is running.
task-5 is running.
task-6 is running.
task-7 is running.
task-8 is running.
task-9 is running.
task-0 is running.
task-1 is running.
将”线程池的拒绝策略”由DiscardPolicy修改为CallerRunsPolicy之后,当有任务添加到线程池被拒绝时,线程池会将被拒绝的任务添加到”线程池正在运⾏的线程”中取运⾏。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。