java 线程池ThreadPoolExecutor的拒绝策略有:
/**
* A handler for rejected tasks that runs the rejected task
* directly in the calling thread of the {@code execute} method,
* unless the executor has been shut down, in which case the task
* is discarded.
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
...
}
/**
* A handler for rejected tasks that throws a
* {@code RejectedExecutionException}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
...
}
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
...
}
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
...
}
- CallerRunsPolicy : 当线程池和队列都满时,任务将会被任务的调用方线程执行,如果线程池关闭,那么任务将会被抛弃
- AbortPolicy :当线程池和队列都满时,再有任务进来直接抛出RejectedExecutionException异常
- DiscardPolicy: 当线程池和队列都满时,再有任务进来,默默的将任务抛弃
- DiscardOldestPolicy: 当线程池和队列都满时,再有任务进来,抛弃最老的未处理的任务,然后重试该新进来的任务,如果线程池关闭,那么任务将会被抛弃
我们来看一个例子:
public static void main(String [] args) throws ExecutionException, InterruptedException {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,1,
500,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(1),
new ThreadPoolExecutor.CallerRunsPolicy()
//new ThreadPoolExecutor.DiscardPolicy()
//new ThreadPoolExecutor.DiscardOldestPolicy()
//new ThreadPoolExecutor.AbortPolicy()
);
Future<String> taskOne = threadPoolExecutor.submit(()->{
System.out.println("taskOne start...");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("taskOne 沉睡2秒结束...");
return Thread.currentThread().getName();
});
Future<String> taskTwo = threadPoolExecutor.submit(()->{
System.out.println("taskTwo start...");
return Thread.currentThread().getName();
});
Future<String> taskThree = threadPoolExecutor.submit(()->{
System.out.println("taskThree start...");
return Thread.currentThread().getName();
});
System.out.println("taskOne:" + taskOne.get());
System.out.println("taskTwo:" + taskTwo.get());
System.out.println("taskThree:" + taskThree.get());
threadPoolExecutor.shutdown();
}
上述例子中创建了一个核心线程池数与最大线程池数都为1,阻塞队列长度也为1的线程池。然后启动三个任务,其中第一个任务执行等待2秒。
taskOne 占用了线程池中的唯一那个线程,taskTwo 进入了阻塞队列,这时队列已满,taskThree再进入线程池触发对应的策略。
- 当使用CallerRunsPolicy策略时打印:
taskOne start...
taskThree start...
taskOne 沉睡2秒结束...
taskOne:pool-1-thread-1
taskTwo start...
taskTwo:pool-1-thread-1
taskThree:main
可以看出taskOne和taskTwo执行者都是线程池内的那个线程,而taskThree的执行线程则是调用taskThree的main函数主线程
- 当使用DiscardPolicy()策略时打印:
taskOne start...
taskOne 沉睡2秒结束...
taskOne:pool-1-thread-1
taskTwo start...
taskTwo:pool-1-thread-1
默默抛弃策略不再打印taskThree 相关信息,并且程序在taskThree.get()处阻塞,线程池迟迟无法关闭。
- 当使用DiscardOldestPolicy()策略时打印:
taskOne start...
taskOne 沉睡2秒结束...
taskOne:pool-1-thread-1
taskThree start...
taskThree再进入线程池时,线程池根据策略把未执行的taskTwo给抛弃了,然后重试执行了taskThree,所以打印了taskThree start...
,但是,因为taskTwo 已被抛弃所以在调用taskTwo.get()时发生了阻塞。�所以没有System.out.println("taskThree:" + taskThree.get());
相关的信息
- 当使用AbortPolicy()策略时打印:
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@31cefde0 rejected from java.util.concurrent.ThreadPoolExecutor@439f5b3d[Running, pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 0]
taskOne start...
taskOne 沉睡2秒结束...
taskTwo start...
main主线程在taskThree的submit()时抛出异常,后面的信息都不打印了。