首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

面试官:说说停止线程池的执行流程?

编程知识
2024年09月12日 15:57

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

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

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 方法(钩子方法)可能用于在关闭时执行一些特定的清理或自定义操作,比如释放资源等。
  6. 释放锁
  7. 尝试终止线程池:如果所有任务已完成的情况下,会真正的终止线程池。

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

课后思考

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

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

From:https://www.cnblogs.com/vipstone/p/18410593
本文地址: http://shuzixingkong.net/article/1951
0评论
提交 加载更多评论
其他文章 架构师备考的一些思考(三)
前言 这个考题的大部分内容,我感觉都是我们会的,但所有的考题都穿上了马甲,穿上马甲我们就不好认了,而且如果是一个两个人穿马甲,还好推断,如果1000人穿马甲,你识别的概率就会急速下降。 有些题的内容则是即无法识别,也无法背,因为它也没有个前因后果,完全是出题人拍脑袋想的,所以,这种题我们是无法通过知
架构师备考的一些思考(三)
.net core8 使用Swagger(附当前源码)
说明 该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。 该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。 说明:OverallAuth2.0 是一个简单、易懂、功能强大的权限+可视化流程管理系统。 有兴趣的朋友,请关注我吧(*^▽^*)
.net core8 使用Swagger(附当前源码) .net core8 使用Swagger(附当前源码) .net core8 使用Swagger(附当前源码)
掌握 C++17:结构化绑定与拷贝消除的妙用
C++17 特性示例 1. 结构化绑定(Structured Binding) 结构化绑定允许你用一个对象的元素或成员同时实例化多个实体。 结构化绑定允许你在声明变量的同时解构一个复合类型的数据结构(如 结构体,std::tuple, std::pair, 或者 std::array)。这样可以方便
浅谈 C# 中的顶级语句
前言 在C# 9版本中引入了一项新特性:顶级语句,这一特性允许在不显式定义 Main 方法的情况下直接编写代码。 传统的写法 namespace&#160;TestStatements{ internal&#160;class&#160;Program { static&#160;void&#160
浅谈 C# 中的顶级语句 浅谈 C# 中的顶级语句
SpringCloud入门(二)服务间调用和案例
一、微服务拆分注意事项微服务拆分注意事项:1.单一职责:不同微服务,不要重复开发相同业务2.数据独立:不要访问其它微服务的数据库3.面向服务:将自己的业务暴露为接口,供其它微服务调用 1.微服务需要根据业务模块拆分,做到单一职责,不要重复开发相同业务2.微服务可以将业务暴露为接口,供其它微服务使用3
SpringCloud入门(二)服务间调用和案例 SpringCloud入门(二)服务间调用和案例
【解题报告】P8478 「GLR-R3」清明
P8478 「GLR-R3」清明 参考了出题人题解和 xcyyyyyy 大神的题解,强推前两篇。 拿到题完全没思路怎么办??? 人类智慧的巅峰,思维量的登峰造极。 换句话说就是非人题目,不过不得不说 GLR 的题是真的好,难度也是真的高。 首先我们需要看懂题面,这是第一个难点。 题面大意如下: 对于
【解题报告】P8478 「GLR-R3」清明
简单聊聊 CORS 攻击与防御
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。 本文作者:霁明 什么是CORS CORS(跨域资源共享)是一种基于HTTP头的机制,可以放宽浏览器的同源策略,实现不同域名网站之间的通信。 前置知识 同源定义:协议、域
简单聊聊 CORS 攻击与防御 简单聊聊 CORS 攻击与防御 简单聊聊 CORS 攻击与防御
41岁的大龄程序员,苟着苟着,要为以后做打算了
最近看到 薰衣草写的《写在临近40岁的年龄》 多少有点感慨,直到看到初九写的《40岁大龄失业程序猿,未来该何去何从》 ,有点绷不住了,如果说薰衣草写的有点抒情,离心里的距离还有点远,而初九的情况简直像照进现实的镜子,映射出未来可能遇到的困境。 许多人在想:“活人难道真会被尿憋死?”觉得桥到床头自然直