欢迎来到狗哥多线程系列连载。本篇是线程相关的第七篇,前六篇分别是:
因为线程池是在提交任务时根据情况执行拒绝策略的,而提交任务涉及两个方法:execute 和 sumbit。在说拒绝策略之前,先谈谈这两方法的区别。
先看看 submit 的源码:可以看到它最终还是调用 execute 方法。与 execute 的区别就是:可以接收线程池执行的返回值,而 execute () 不能接收返回值。
public Future < ? > submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture < Void > ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
再看 execute 源码,注释写得很清楚了,简单说下,分为三步:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 当前工作的线程数小于核心线程数
if (workerCountOf(c) < corePoolSize) {
// 创建新的线程执行此任务
if (addWorker(command, true))
return;
c = ctl.get();
}
// 检查线程池是否处于运行状态,如果是则把任务添加到队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 再次检查线程池是否处于运行状态,防止在第一次校验通过后线程池关闭
// 如果是非运行状态,则将刚加入队列的任务移除,并执行拒绝策略
if (!isRunning(recheck) && remove(command))
reject(command);
// 如果线程池的线程数为 0 时(当 corePoolSize 设置为 0 时会发生)
// 新建线程执行任务
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
// 核心线程都在忙且队列都已爆满,尝试新启动一个线程执行失败
} else if (!addWorker(command, false))
// 执行拒绝策略
reject(command);
}
Java 给我们提供了拒绝策略,创建线程池时就可以指定拒绝策略,比如:
newThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS, new LinkedBlockingQueue < > (),
new ThreadPoolExecutor.AbortPolicy());
当然,你也可以自己实现~
上面了解了拒绝策略的执行时机,再来看看 Java 给我们提供的拒绝策略。分为四种,关系如下:
拒绝策略.png
逐个聊聊它们的特点:
本文从源码分析了拒绝策略的执行时机并详细介绍了 Java 提供的四种拒绝策略,相信大家看完会有所收获。选用哪种线程池是根据你自己的业务而定的,实践出真知。
-END-
如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「一个优秀的废人」,关注后回复「 1024」送你一套完整的 java 教程(包括视频)。回复「 电子书」送你Java、C、C++、Linux、Go、Python、数据库、前端、计算机基础、人工智能、数据结构与算法、设计模式以及面试相关电子书 。
教程节选