说说停止线程池的执行流程?

对于我们使用的线程池 ThreadPoolExecutor 来说,停止线程池的方法有以下两个:

  1. shutdown() :优雅的关闭线程池,即不再接受新任务,但会等待已提交任务(包括正在执行的任务和在队列中等待的任务)执行完毕。等待所有任务都执行完毕后,线程池才会进入终止状态
  2. shutdownNow() :尝试停止所有正在执行的任务,并返回等待执行的任务列表。<font style="color:rgba(0, 0, 0, 0.85);">正在执行的任务可能会被中断</font><font style="color:rgba(0, 0, 0, 0.85);">,适用于</font>需要立即停止线程池,但不关心正在执行的任务是否立即完成的情况下。

1.代码演示

下面通过代码案例,咱们来了解一下 shutdown() 和 shutdownNow() 方法的具体使用。

1.1 shutdown() 方法执行

我们将线程池核心和最大线程数都设置为 2,任务队列可以存储 10 个任务,一次性添加了 5 个任务,每个任务执行 2s 以上,添加完任务之后执行停止方法,并在 1s 之后尝试添加另一个新任务,如下代码所示:

复制代码
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExecutorShutdownTest {
    public static void main(String[] args) {
        // 创建线程
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2,
                2,
                1000,
                TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(10),
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println("执行拒绝策略");
                    }
                });
        // 添加任务
        for (int i = 0; i < 5; i++) {
            executor.submit(() -> {
                String tName = Thread.currentThread().getName();
                System.out.println(tName + ":开始执行任务!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(tName + ":结束执行任务!");
            });
        }
        // 停止线程
        executor.shutdown();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 添加新任务
        executor.submit(() -> System.out.println("最后一个新任务"));
    }
}

以上程序的执行结果如下:

从以上结果可以看出,执行 shutdown() 方法后,程序会等待线程池中的所有任务全部执行完在关闭,再次期间线程池会拒绝加入新任务,并调用线程池的拒绝策略

1.2 shutdownNow()方法执行

如果将 shutdown() 方法换成 shutdownNow() 方法后,以上程序的执行结果如下:

也就是说,调用 shutdownNow() 之后,正在执行的任务会被立即停止,且任务队列中未执行的任务也会被清除,调用 shutdownNow() 方法后新加入的任务会被拒绝,并执行线程池的拒绝策略

2.shutdown()执行流程

shutdown() 方法执行源码如下:

复制代码
public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(SHUTDOWN);
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
}

该源码执行流程如下:

  1. 加锁:在多线程环境下,关闭操作涉及到修改关键状态和执行一些可能影响多个线程的操作。使用锁可以确保这些操作的原子性和一致性,避免多个线程同时进行关闭操作导致数据不一致或出现意外情况
  2. 检查关闭权限:在关闭之前进行状态检查可以确保关闭操作是合法的,避免在不适当的时候进行关闭。推进状态可以让其他代码部分能够根据当前执行器的状态做出正确的反应。
  3. 将状态设置为 SHUTDOWN:阻止新任务提交但完成现有任务。
  4. 中断空闲线程
  5. 调用 onShutdown 方法(钩子方法) :<font style="color:rgba(0, 0, 0, 0.85);">可能用于</font><font style="color:rgba(0, 0, 0, 0.85);">在关闭时执行一些特定的清理或自定义操作,比如释放资源</font><font style="color:rgba(0, 0, 0, 0.85);">等。</font>
  6. <font style="color:rgba(0, 0, 0, 0.85);">释放锁</font><font style="color:rgba(0, 0, 0, 0.85);">。</font>
  7. 尝试终止线程池:如果所有任务已完成的情况下,会真正的终止线程池。

shutdown() 方法的执行流程如下图所示:

课后思考

为什么需要关闭线程池?关闭线程池的场景有哪些?说说 shutdownNow() 的执行流程?

作为程序员,持续学习和充电非常重要,作为开发者,我们需要保持好奇心和学习热情,不断探索新的技术,只有这样,我们才能在这个快速发展的时代中立于不败之地。低代码也是一个值得我们深入探索的领域,让我们拭目以待,它将给前端世界带来怎样的变革,推荐一个低代码工具。

应用地址: https://www.jnpfsoft.com
开发语言:Java/.net

这是一个基于Flowable引擎(支持java、.NET),已支持MySQL、SqlServer、Oracle、PostgreSQL、DM(达梦)、 KingbaseES(人大金仓)6个数据库,支持私有化部署,前后端封装了上千个常用类,方便扩展,框架集成了表单、报表、图表、大屏等各种常用的 Demo方便直接使用。

至少包含表单建模、流程设计、报表可视化、代码生成器、系统管理、前端 UI 等组件,这种情况下我们避免了重复造轮子,已内置大量的成熟组件,选择合适的组件进行集成或二次开发复杂功能,即可自主开发一个属于自己的应用系统。

相关推荐
飞飞-躺着更舒服3 分钟前
【QT】实现电子飞行显示器(改进版)
开发语言·qt
w_312345413 分钟前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安15 分钟前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA19 分钟前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
Q_192849990626 分钟前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟43 分钟前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S1 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos1 小时前
c++------------------函数
开发语言·c++
yuanbenshidiaos1 小时前
C++----------函数的调用机制
java·c++·算法
程序员_三木1 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js