线程池的拒绝策略你们一般用的时候选择哪种?
1 个回答
世间万物,唯有过往伤人最深。乱舞狂刀在 Java 中,线程池提供了多种拒绝策略,用于处理任务提交到线程池时,线程池已满的情况。以下是常见的线程池拒绝策略及其适用场景和详细解释。 #### 1. **AbortPolicy(默认策略)** **描述**: - 直接抛出 `RejectedExecutionException` 异常,通知调用者任务被拒绝。 **适用场景**: - 适用于不希望任务被丢弃而且需要立即得到通知的场景。 - 例如,在金融交易系统中,必须确保每个交易请求都被处理或明确被拒绝。 **代码示例**: ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new ArrayBlockingQueue<>(capacity), new ThreadPoolExecutor.AbortPolicy() ); ``` #### 2. **CallerRunsPolicy** **描述**: - 调用 `execute` 方法的线程(通常是提交任务的线程)来执行任务,这种策略不会丢弃任务,但会影响提交任务的线程。 **适用场景**: - 适用于不希望任务被丢弃且能够容忍提交任务的线程被阻塞或执行任务的场景。 - 例如,在一些非实时要求的后台处理系统中,可以允许提交任务的线程承担一部分任务执行。 **代码示例**: ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new ArrayBlockingQueue<>(capacity), new ThreadPoolExecutor.CallerRunsPolicy() ); ``` #### 3. **DiscardPolicy** **描述**: - 直接丢弃任务,不予任何处理或通知。 **适用场景**: - 适用于可以容忍任务被丢弃的场景,不需要特别处理被拒绝的任务。 - 例如,在日志系统中,偶尔丢失日志记录是可以接受的。 **代码示例**: ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new ArrayBlockingQueue<>(capacity), new ThreadPoolExecutor.DiscardPolicy() ); ``` #### 4. **DiscardOldestPolicy** **描述**: - 丢弃队列中最旧的未处理任务,然后重新尝试执行当前任务。 **适用场景**: - 适用于希望确保新的任务能被执行,可以容忍丢弃队列中最旧任务的场景。 - 例如,在某些实时性要求高的系统中,更希望处理新的任务而不是旧的任务。 **代码示例**: ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new ArrayBlockingQueue<>(capacity), new ThreadPoolExecutor.DiscardOldestPolicy() ); ``` ### 如何选择合适的拒绝策略 选择合适的拒绝策略应根据具体的应用场景和业务需求: 1. **任务重要性和实时性**: - 如果任务非常重要且不能丢弃,考虑使用 `AbortPolicy` 或 `CallerRunsPolicy`。 - 如果任务可以丢弃且需要处理最新的任务,考虑使用 `DiscardOldestPolicy`。 2. **系统的容错能力**: - 如果系统能容忍部分任务丢失,且不需要处理所有任务,`DiscardPolicy` 是一个简单的选择。 - 如果系统不能容忍任务丢失,`CallerRunsPolicy` 可以让提交任务的线程处理任务,避免任务丢失。 3. **任务处理的代价和影响**: - 如果处理任务的代价较高,且提交任务的线程不能承担额外的任务处理负载,避免使用 `CallerRunsPolicy`。 ### 代码示例 以下是一个综合示例,展示如何配置和使用不同的拒绝策略: ```java import java.util.concurrent.*; public class ThreadPoolRejectPolicyExample { public static void main(String[] args) { // 使用不同的拒绝策略创建线程池 ThreadPoolExecutor executorAbort = createThreadPoolExecutor(new ThreadPoolExecutor.AbortPolicy()); ThreadPoolExecutor executorCallerRuns = createThreadPoolExecutor(new ThreadPoolExecutor.CallerRunsPolicy()); ThreadPoolExecutor executorDiscard = createThreadPoolExecutor(new ThreadPoolExecutor.DiscardPolicy()); ThreadPoolExecutor executorDiscardOldest = createThreadPoolExecutor(new ThreadPoolExecutor.DiscardOldestPolicy()); // 提交任务到线程池 for (int i = 0; i < 20; i++) { int taskNumber = i; executorAbort.execute(() -> System.out.println("Task executed by AbortPolicy: " + taskNumber)); executorCallerRuns.execute(() -> System.out.println("Task executed by CallerRunsPolicy: " + taskNumber)); executorDiscard.execute(() -> System.out.println("Task executed by DiscardPolicy: " + taskNumber)); executorDiscardOldest.execute(() -> System.out.println("Task executed by DiscardOldestPolicy: " + taskNumber)); } // 关闭线程池 executorAbort.shutdown(); executorCallerRuns.shutdown(); executorDiscard.shutdown(); executorDiscardOldest.shutdown(); } private static ThreadPoolExecutor createThreadPoolExecutor(RejectedExecutionHandler handler) { return new ThreadPoolExecutor( 2, // corePoolSize 4, // maximumPoolSize 60, // keepAliveTime TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), // 工作队列容量 handler // 拒绝策略 ); } } ``` ### 总结 选择合适的线程池拒绝策略需要综合考虑任务的实时性、重要性和系统的容错能力。常见的拒绝策略包括 `AbortPolicy`、`CallerRunsPolicy`、`DiscardPolicy` 和 `DiscardOldestPolicy`,每种策略适用于不同的场景。通过配置合适的拒绝策略,可以有效地处理线程池饱和时的任务调度问题。编辑于 2024-09-12 02:04 •IP属地 美国举报评论收藏
公众号进入网站体验更佳

