面试题答案
一键面试1. AbortPolicy(终止策略)
- 实现原理:当任务无法在当前线程池执行时(队列已满且线程数达到最大线程数),该策略会抛出
RejectedExecutionException
异常,阻止系统正常运行。 - 应用场景:适用于对任务执行失败非常敏感的场景,比如一些关键业务流程,需要立即知晓任务未被执行的情况,以便及时处理异常。例如,金融交易系统中的交易操作,如果交易任务无法执行,抛出异常可以及时提醒运维人员排查问题,防止交易丢失。
2. CallerRunsPolicy(调用者运行策略)
- 实现原理:当任务被拒绝添加到线程池时,该策略会让调用 execute 方法的线程(通常是主线程)来执行这个任务。这样做可以减少新任务的提交速度,同时利用调用者线程的资源来执行任务。
- 应用场景:适用于对响应时间要求不高,但希望系统能尽量处理任务而不丢弃的场景。比如在一个简单的日志记录系统中,即使任务暂时无法被线程池处理,由调用者线程执行也不会对系统造成太大影响,并且能保证日志记录不丢失。
3. DiscardPolicy(丢弃策略)
- 实现原理:当任务被拒绝添加到线程池时,该策略直接默默丢弃这个任务,不做任何处理。
- 应用场景:适用于那些对任务执行与否不太敏感,任务执行失败不会对系统造成严重后果的场景。例如,在一个统计系统中,统计数据的任务偶尔丢失一两个对整体统计结果影响不大,此时可以使用该策略。
4. DiscardOldestPolicy(丢弃最旧任务策略)
- 实现原理:当任务被拒绝添加到线程池时,该策略会丢弃队列中最旧的任务(即等待时间最长的任务),然后尝试将新任务添加到队列中。如果再次失败(队列已满等情况),则会丢弃新任务。
- 应用场景:适用于任务具有时效性的场景,新任务比旧任务更重要。比如在一个实时行情数据更新系统中,新的行情数据比旧数据更有价值,丢弃旧数据的任务而优先处理新任务可以保证系统显示的数据更接近实时情况。
自定义拒绝策略实现
- 步骤:
- 实现
RejectedExecutionHandler
接口。 - 重写
rejectedExecution
方法,在该方法中编写自定义的拒绝处理逻辑。
- 实现
- 示例代码:
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 自定义处理逻辑,例如记录日志
System.out.println("Task " + r.toString() + " rejected from " + executor.toString());
// 也可以进行任务重试等操作
}
}
使用时,在创建线程池时将自定义的拒绝策略实例传递给线程池构造函数:
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2,
4,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(2),
new CustomRejectedExecutionHandler());
for (int i = 0; i < 10; i++) {
executor.execute(() -> {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " is running");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
}
}