本文详细解析了Java中线程池的拒绝策略,帮助开发者理解并合理选择或定制适合应用需求的拒绝策略,以优化程序性能。
Java线程池的拒绝策略是指当线程池中的线程数量达到最大值时如何处理新的任务提交的方式。这个策略是由RejectedExecutionHandler接口定义的,并提供了四种默认的拒绝策略:CallerRunsPolicy、AbortPolicy、DiscardPolicy和DiscardOldestPolicy。
首先了解一下线程池的基本概念。线程池是池化思想的应用,其目的是为了提高系统的性能和效率。在Java中,ThreadPoolExecutor类实现了这一功能,它定义了三个重要的参数:corePoolSize(核心线程数)、workQueue(阻塞队列)以及maximumPoolSize(最大线程数)。当提交的任务数量超过(workQueue.size() + maximumPoolSize)时会触发拒绝策略。RejectedExecutionHandler接口中的rejectedExecution方法用于定制具体的执行逻辑。
Java提供了以下四种默认的拒绝策略:
1. **CallerRunsPolicy**:如果任务被拒,只要线程池没有关闭,则使用调用线程直接运行该任务。适合于并发量较小、性能要求不高且不允许失败的情况。
2. **AbortPolicy**:丢弃任务,并抛出RejectedExecutionException异常信息。这是默认的拒绝策略。
3. **DiscardPolicy**:简单地抛弃被拒的任务,不做其他处理。
4. **DiscardOldestPolicy**:如果线程池未关闭且队列非空,则移除最旧的一个任务并尝试重新提交当前新来的任务。
在实际应用中,根据不同的需求可以选择合适的拒绝策略。例如,在高并发情况下使用CallerRunsPolicy可以避免系统资源被过多消耗;需要确保所有任务被执行的情况下则可选用AbortPolicy来抛出异常信息以引起注意。
下面是一个简单的示例代码展示如何配置ThreadPoolExecutor和RejectedExecutionHandler接口实现线程池的拒绝策略:
```java
import java.util.concurrent.*;
import org.slf4j.*;
@Slf4j
public class T2 {
public static void main(String[] args) throws Exception {
int corePoolSize = 5;
int maximumPoolSize = 10;
long keepAliveTime = 5;
BlockingQueue workQueue = new LinkedBlockingQueue<>(10);
// 使用AbortPolicy作为拒绝策略
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.SECONDS, workQueue, handler);
for (int i = 0; i < 20; ++i) {
executor.execute(() -> log.info(执行任务));
}
// 等待所有任务完成
executor.shutdown();
executor.awaitTermination(1L, TimeUnit.DAYS);
}
}
```
在这个示例中,我们创建了一个ThreadPoolExecutor实例,并设置了AbortPolicy作为拒绝策略。当提交的任务数量超过核心线程数和最大线程数之和时,将会抛出RejectedExecutionException异常信息。