当线程池的有界工作队列排满才需要使用饱和策略,饱和策略要么拒绝新的请求,要么要求请求被延时执行。Java提供了几种拒绝提交任务的方案,可以通过ThreadPoolExecutor类的setRejectedExecutionHandler方法来设置饱和策略。具体参数如下:
<!--[if !supportLists]-->1、
1、CallerRunsPolicy
2、AbortPolicy
3、DiscardPolicy
4、DiscardOldestPolicy
第一种策略为Caller-runs策略,即该线程的执行有调用的这个线程来执行,调用的线程会暂停原来的任务,转而去执行该任务,该任务执行完成后继续执行原来的任务。测试用例如下:
public static void main(String[] args) {
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1);
ThreadPoolExecutor exec = new ThreadPoolExecutor(1, 1, 100,
TimeUnit.SECONDS,
workQueue);
exec.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
System.out.println(new Date());
for(int i=0;i<5;i++) {
exec.execute(new Runnable() {
@Override
public void run() {
System.out.println("task run : " + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
System.out.println(new Date());
exec.shutdown();
}
程序运行结果如图所示:
主线程提交了创建了一个ThreadPoolExecutor,并且容量为1,队列为1,此时最多可以提交两个线程。因为在提交第三个任务的同时,线程池总的线程正在运行,等待队列已满,新的任务无处可放,这里的Caller-runs策略吧这个任务交由调用该请求的线程,也就是main线程来执行这个任务。可以看到,该主线程本身可以在很小的时间内提交任务并结束,但由于他需要执行一定的任务,被延迟了4秒才执行完毕,可以预见main线程在这期间运行了两次任务。
第二种策略为AbortPolicy,该策略保证在线程池满的情况下任何试图提交任务到该线程池的线程的线程均会抛出,RejectedExecutionException,该异常导致调用线程的终止。但这种异常时可以捕获的(非检查型异常)。
第三种策略为DiscardPolicy,该策略保证任何试图向满的线程池提交任务时,该任务的提交会立即返回,任务不会被提交,并且不会抛出任何形式的异常。
最后一种为DiscardOldestPolicy,这种模式下,将会抛弃下一个将要执行的任务,然后把刚提交的任务添加到任务队列,等待执行。