您的位置:首页 > 其它

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

2019-05-23 09:40 951 查看

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

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

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

1、直接丢弃(DiscardPolicy)

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

3、抛异常(AbortPolicy)

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

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

代码如下:

[code]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线程,其他线程并没有在队列里,也不会被消费。

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

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

[code]
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://www.geek-share.com/detail/2681402480.html

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: