原创

java面试题-线程池有哪几种拒绝策略?

线程池是多线程编程中的关键组件,而拒绝策略是线程池处理任务超负荷时的重要机制。本教程将深入讨论线程池提供的四种拒绝策略,包括 AbortPolicyCallerRunsPolicyDiscardOldestPolicyDiscardPolicy,并介绍如何实现自定义的拒绝策略。通过源码解析和示例代码,帮助初学者深入理解线程池的异常处理机制。

1. AbortPolicy(默认策略)

AbortPolicy 是线程池默认的拒绝策略,其行为是直接抛出异常。当线程池无法处理新提交的任务时,会调用 RejectedExecutionHandlerrejectedExecution 方法,该方法默认的实现就是抛出 RejectedExecutionException

示例代码

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(queueCapacity),
        new ThreadPoolExecutor.AbortPolicy()
);

executor.execute(() -> System.out.println("Task 1"));
// 添加更多任务

2. CallerRunsPolicy

CallerRunsPolicy 策略会使用调用者所在的线程来执行被拒绝的任务。这意味着当线程池拒绝任务时,将由提交任务的线程来执行该任务,从而避免任务丢失。

示例代码

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(queueCapacity),
        new ThreadPoolExecutor.CallerRunsPolicy()
);

executor.execute(() -> System.out.println("Task 1"));
// 添加更多任务

3. DiscardOldestPolicy

DiscardOldestPolicy 策略会丢弃阻塞队列中最前面的任务,并执行当前被拒绝的任务。这样可以保留最新提交的任务,避免任务丢失。

示例代码

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(queueCapacity),
        new ThreadPoolExecutor.DiscardOldestPolicy()
);

executor.execute(() -> System.out.println("Task 1"));
// 添加更多任务

4. DiscardPolicy

DiscardPolicy 策略会直接丢弃被拒绝的任务,没有任何处理。这可能导致任务丢失,适用于对任务实时性要求不高的场景。

示例代码

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(queueCapacity),
        new ThreadPoolExecutor.DiscardPolicy()
);

executor.execute(() -> System.out.println("Task 1"));
// 添加更多任务

5. 自定义拒绝策略

除了以上四种内置的拒绝策略,我们还可以实现自定义的拒绝策略,例如记录日志、持久化到数据库等。只需要实现 RejectedExecutionHandler 接口,并在 rejectedExecution 方法中定义自己的处理逻辑。

示例代码

public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 自定义处理逻辑,例如记录日志
        System.out.println("Task rejected. Logging...");
    }
}

// 使用自定义拒绝策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(queueCapacity),
        new CustomRejectedExecutionHandler()
);

executor.execute(() -> System.out.println("Task 1"));
// 添加更多任务

源码解析

下面通过源码解析,更详细地说明线程池拒绝策略的实现细节。

源码解析

// ThreadPoolExecutor 源码
public class ThreadPoolExecutor extends AbstractExecutorService {
    // ... 省略其他属性 ...

    public ThreadPoolExecutor(
            int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
            TimeUnit unit,
            BlockingQueue<Runnable> workQueue,
            RejectedExecutionHandler handler
    ) {
        // ... 省略初始化代码 ...
        this.handler = handler != null ? handler : new AbortPolicy();
        // ... 省略其他初始化代码 ...
    }

    public void execute(Runnable command) {
        // ... 省略其他执行逻辑 ...
        if (runStateAtLeast(ctl.get(), SHUTDOWN)
                && ! (Thread.currentThread() instanceof Worker))
            reject

(command);
        // ... 省略其他执行逻辑 ...
    }

    private void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }

    // ... 省略其他方法 ...
}

// AbortPolicy 源码
public static class AbortPolicy implements RejectedExecutionHandler {
    public AbortPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

在源码中,可以看到线程池的构造函数接受一个 RejectedExecutionHandler 参数,用于处理被拒绝的任务。默认情况下,如果未提供自定义的 RejectedExecutionHandler,则使用 AbortPolicy

总结

通过本教程的详细讲解,我们深入了解了线程池提供的四种拒绝策略,包括它们的特点和适用场景。此外,我们还介绍了如何实现自定义的拒绝策略,以满足特定需求。理解拒绝策略对于合理配置线程池、保障任务处理的稳定性至关重要。

正文到此结束
本文目录