Q: 什么时候需要使用拒绝策略呢?
A: 当任务数量超过系统实际承载能力的时候就要用到拒绝策略了,可以说它是系统超负荷运行的补救措施。简言之,就是线程用完,队列已满,无法为新任务服务,则需一套机制来合理的处理这些问题。
JDK 提供了四种内置拒绝策略,我们要理解并记住,有如下的四种:
1、DiscardPolicy: 默默丢弃无法处理的任务,不予任何处理
2、DiscardOldestPolicy: 丢弃队列中最老的任务, 尝试再次提交当前任务
3、AbortPolicy: 直接抛异常,阻止系统正常工作。
4、CallerRunsPolicy: 将任务分给调用线程来执行,运行当前被丢弃的任务,这样做不会真的丢弃任务,但是提交的线程性能有可能急剧下降。
以下是我们通常的使用方式:
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 ());
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
但有时候我们需要对改接口进行扩展,来满足特别的需求就需要自定义了。
拒绝策略的接口实现
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r,
ThreadPoolExecutor executor);
}
自定义拒绝策略的代码示例
public class RejectThreadPoolDemo {
public static class MyTask implements Runnable {
@Override
public void run() {
System.out.println(System.currentTimeMillis()
+ ":Thread ID:" + Thread.currentThread().getId());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) throws InterruptedException {
MyTask myTask = new MyTask();
ExecutorService executorService = new ThreadPoolExecutor(5, 5, 0L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(10),
Executors.defaultThreadFactory()
, new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//打印丢弃的任务
System.out.println(r.toString() + " is discard");
}
});
for (int i = 0; i < 100; i++) {
executorService.submit(myTask);
Thread.sleep(10);
}
}
}
上面自定义了一个线程池有5个常驻线程,最大线程数量也是5个,等待队列设为10,同时在这里自定义了拒绝策略,打印被丢弃的任务信息。
输出如下:
java.util.concurrent.FutureTask@1f32e575 is discard
java.util.concurrent.FutureTask@279f2327 is discard
java.util.concurrent.FutureTask@2ff4acd0 is discard
java.util.concurrent.FutureTask@54bedef2 is discard
1528709221737:Thread ID:10
1528709221752:Thread ID:11
思考:
- Java中有哪些无界队列和有界队列?
- 为什么生产上不能使用无界队列?
下一次分享让我们探讨一下有界、无界队列对ThreadPoolExcutor执行的影响,欢迎小伙伴们留言讨论~~