Java线程池拒绝策略:当任务太多时,线程池怎么说“不”?
Java线程池拒绝策略:当任务太多时,线程池怎么说“不”?
在Java并发编程的世界里,线程池是一个非常重要的工具。它可以帮助我们管理和复用线程,提高程序的执行效率。但是,当我们向线程池提交的任务数量超过了它的处理能力时,会发生什么呢?这时,线程池就需要一种机制来处理这些“多余的”任务,这就是所谓的拒绝策略。
什么是线程池拒绝策略?
当你向线程池提交任务时,如果当前正在运行的任务数已经达到了线程池的最大容量,并且队列也满了,那么线程池就无法再接受新的任务了。此时,线程池会根据预先设定的拒绝策略来处理这个新来的任务。
Java线程池的拒绝策略有哪些?
Java提供了四种内置的拒绝策略,它们分别是:
- AbortPolicy(默认策略)
这是最常见的拒绝策略。当线程池无法处理新的任务时,它会抛出一个RejectedExecutionException异常。这种策略简单粗暴,直接告诉任务提交者:“我忙不过来了,你另寻出路吧。” - class MyTask implements Runnable { public void run() { System.out.println("任务正在执行"); } } public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(2)); for (int i = 0; i < 5; i++) { final int taskNumber = i; executor.execute(() -> { System.out.println("任务 " + taskNumber + " 开始执行"); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("任务 " + taskNumber + " 执行完毕"); }); } executor.shutdown(); }
- 当提交第5个任务时,线程池会抛出RejectedExecutionException异常。
- CallerRunsPolicy
这种策略会让提交任务的线程自己去执行这个任务。这相当于把任务的执行权交回给提交者,让提交者自己来处理这个任务。 - ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(2), new ThreadPoolExecutor.CallerRunsPolicy()); executor.execute(() -> { System.out.println("任务执行中"); }); // 提交第5个任务时,主线程会执行这个任务
- DiscardPolicy
这种策略非常干脆,直接丢弃新来的任务而不做任何处理。这种方式适合那些不重要或者可以忽略的任务。 - ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(2), new ThreadPoolExecutor.DiscardPolicy()); executor.execute(() -> { System.out.println("任务执行中"); }); // 提交第5个任务时,任务会被默默丢弃
- DiscardOldestPolicy
这种策略会丢弃队列中最老的那个任务,然后尝试重新提交当前任务。这种方法通常用于需要保留最新任务的情况。 - ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(2), new ThreadPoolExecutor.DiscardOldestPolicy()); executor.execute(() -> { System.out.println("任务执行中"); }); // 提交第5个任务时,最老的一个任务会被丢弃
如何自定义拒绝策略?
如果你觉得Java提供的这几种拒绝策略都不够满足你的需求,你可以自定义自己的拒绝策略。这只需要实现一个RejectedExecutionHandler接口即可。
class CustomPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("任务被拒绝:" + r.toString());
// 自定义处理方式
}
}
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 2, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(2),
new CustomPolicy());
在这个例子中,我们创建了一个自定义的拒绝策略,当任务被拒绝时,它会打印一条消息。
总结
Java线程池的拒绝策略为我们提供了多种方式来处理线程池满载时的情况。无论是直接抛出异常、让提交者自己执行任务、丢弃旧任务还是自定义处理方式,都给了开发者足够的灵活性来应对各种复杂情况。掌握了这些策略,你就可以更好地控制线程池的行为,从而编写出更健壮和高效的并发程序。