显式关闭线程池的正确姿势

5年经验,还不知道线程池是否需要关闭 前言 大家在日常开发中会经常用多线程,一般为了合理地管理线程,我们一般会通过线程池来创建线程。那么在使用完线程池之后我们需要显式关闭线程池么? 举个栗子 下面我们来通过一个demo看看显式关闭线程池是否有必要 public class TestShutDown { private static void asynExecuteOne() { ExecutorService executor = Executors.newSingleThreadExecutor(); 阅读详情

一、shutdown

提到 Java 线程池的关闭,绝大多数人第一时间想到的是 ExecutorService 的 shutdown 方法。

关于 shutdown 方法,注释上是这么说明的。

/**
 * Initiates an orderly shutdown in which previously submitted
 * tasks are executed, but no new tasks will be accepted.
 * Invocation has no additional effect if already shut down.
 */

大概意思是,当执行了 shutdown 方法后,线程池将等待已提交任务执行完成后关闭,但在此期间不再接收新的任务。

对此,我们编写一段代码来测试 shutdown 的效果。(注意:这段代码是不完整的,具体原因见下文)

package com.bolt.panda;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**
 * Created by panda on 2019/2/13.
 */
public class ShutdownDemo {

    public static void main(String[] args) {
        System.out.println("主线程运行开始!");

        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("pool-%d").build();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(), threadFactory);

        executor.submit(new Task());
        executor.submit(new Task());
        executor.submit(new Task());

        executor.shutdown();

        System.out.println("主线程运行结束!");
    }
}

class Task implements Callable {

    @Override
    public Object call() throws Exception {
        System.out.println("子线程执行中...");
        return null;
    }

}

输出结果为:

主线程运行开始!
子线程执行中...
主线程运行结束!
子线程执行中...
子线程执行中...

Process finished with exit code 0

可见,线程池确实是关闭了,因为程序退出了。这里需要解释一下,若线程池没有关闭,则会一直等待任务,不会出现程序退出的现象(因为我们设置的核心线程数大于 0)。

但是,在这里我们发现了一个问题,主线程先于子线程退出了。这一点在很多情况下是不合理的,因为我们常常需要在多线程任务执行结束后回到主线程处理其他工作,例如统计数据等。那么,有什么办法能实现在线程池关闭前主线程保持阻塞状态么?这时候就需要借助 awaitTermination 方法了。

二、awaitTermination

我们先来看看 awaitTermination 的说明:

/**
 * Blocks until all tasks have completed execution after a shutdown
 * request, or the timeout occurs, or the current thread is
 * interrupted, whichever happens first.
 *
 * @param timeout the maximum time to wait
 * @param unit the time unit of the timeout argument
 * @return {@code true} if this executor terminated and
 *         {@code false} if the timeout elapsed before termination
 * @throws InterruptedException if interrupted while waiting
 */
boolean awaitTermination(long timeout, TimeUnit unit)
    throws InterruptedException;

大体意思是,在主线程调用 shutdown 方法后,若此时再调用 awaitTermination 方法,则主线程会保持阻塞状态,除非发生了以下 3 种情况:

  • 线程池中的所有任务已执行完毕
  • 阻塞时长超过设置的最大阻塞时间
  • 发生了中断异常

此外,只有当检测到线程池所有任务执行完毕时,awaitTermination 方法才会返回 true,否则返回 false。

基于以上,我们可以结合 awaitTermination 实现线程池先于主线程关闭。现在,让我们对之前的代码稍作补充,具体如下:

package com.bolt.panda;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**
 * Created by panda on 2019/2/13.
 */
public class ShutdownDemo {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("主线程运行开始!");

        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("pool-%d").build();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(), threadFactory);

        executor.submit(new Task());
        executor.submit(new Task());
        executor.submit(new Task());

        executor.shutdown();

        while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
            System.out.println("检测到仍有活跃子线程,保持阻塞状态...");
        }

        System.out.println("主线程运行结束!");
    }
}

class Task implements Callable {

    @Override
    public Object call() throws Exception {
        System.out.println("子线程执行中...");
        return null;
    }

}

输出结果为:

主线程运行开始!
子线程执行中...
子线程执行中...
子线程执行中...
主线程运行结束!

Process finished with exit code 0

很明显地看到,主线程不再先于子线程退出,而是在线程池关闭后,再完成最后的收尾工作。

关闭Java线程池的正确方法 线程中断的含义,并不是强制把运行中的线程给“咔嚓”中断,而是把线程的中断标志位置为true,这样等线程之后阻塞(wait、join、sleep)的时候,就会抛出 InterruptedException,程序通过捕获 InterruptedException 来做一定的善后处理,然后让线程退出。这里,如果 tryLock() 成功,说明对应的 woker 是一个空闲的,没有在执行任务的线程,如果没成功,说明对应的 worker 正在执行任务。实例代码如下,一个线程池,提交了三个任务去执行,执行完得半分钟。 阅读详情

相关推荐

保姆级教程:用CANoe手把手复现ECU刷写全流程(含BootLoader三阶段详解)

本文提供了一份详细的CANoe ECU刷写实战指南,涵盖BootLoader三阶段的深度解析。从实验环境搭建到预编程、主编程及后编程阶段,逐步讲解ECU刷写的关键步骤和隐藏逻辑,特别强调UDS诊断和CAN通信的精确控制,帮助开发者掌握ECU刷写的核心技术。

weixin_29234423的博客 531

【Java】如何优雅的关闭线程池

想要优雅的关闭线程池,首先要理解线程中断的含义。其次,关闭线程池有两种方式:shutdown() 和 shutdownNow(),二者最大的区别是 shutdown() 只是把空闲的 woker 置为中断,不影响正在运行的woker,并且会继续把待执行的任务给处理完。shutdonwNow() 则是把所有的 woker 都置为中断,待执行的任务全部抽出并返回,日常工作中更多是使用 shutdown()。

DreamSun的博客 5248

数字孪生在智慧医疗中的5个创新应用:从手术模拟到个性化治疗

数字孪生技术通过创建患者或医疗流程的动态虚拟映射,正在深刻变革智慧医疗。本文重点剖析了其在个性化治疗、手术模拟与导航、药物研发、医院管理优化及慢性病管理五大核心场景的创新应用,展现了如何利用智能映射与数据融合,为精准医疗和高效决策提供强大支持。

weixin_29189003的博客 443

线程池如何关闭

可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池。

wayne_youlu的博客 1392

2025最新正版Autodesk 3ds Max 2022安装教程:从下载到中文环境配置全流程解析

Autodesk 3ds Max 2022是一款专业的三维建模、动画和渲染软件,广泛应用于影视制作、游戏开发、建筑可视化等领域。

waicsdn_haha的博客 1万+

Cadence OrCAD: 层次化设计 Hierarchical Design

详细介绍OrCAD的原理图层次化设计方法。

Fantasy237的博客 1万+

如何关闭线程池

如何关闭线程池

weixin_43862394的博客 2227

使用html和JavaScript实现一个简易的物业管理系统

码实现了一个简易的物业管理系统,主要使用了以下技术和功能: 1.主要技术 使用的技术: HTML: 用于构建网页的基本结构。 包括表单、表格、按钮等元素。 CSS: 用于美化网页的外观和布局。 设置字体、颜色、边距、对齐方式等样式。 JavaScript: 用于处理用户交互和动态更新页面内容。 实现了新增住户、查询住户、编辑住户、删除住户等功能。 处理表单提交事件,验证输入数据,并更新表格显示。 DOM操作: 使用 JavaScript 直接操作 HTML DOM 元素。 动态

weixin_41312759的博客 1778

java如何正确关闭线程以及线程池(代码实践含源码分析)

这个问题是一个高频的面试题 而且在印象中是由stop方法执行或者终端中的kill杀死 但是这些方法直接简单粗暴,很不安全,而且也不推广 不使用stop的方法 之所以不安全不推广是因为: stop方法不管线程逻辑是否完整,都会终止当前正在运行的线程 会破坏其原子逻辑(多线程加了锁之解决资源共享,但是stop会将其所有锁丢弃,造成混乱)

码农研究僧的博客 1万+

【嘉立创EDA】PCB 多层板如何交换内层,4层板交换板层

本文使用嘉立创EDA,描述如何在PCB设计时,如何交换各个板层,特别是4层板需要交换内层时,应该如何操作,以供有需要的读者参考。

l64481000的博客 2015

2025年新发表的语音大模型全双工模型/框架/技术

参考该论文,给出2025年新发表的全双工模型或框架或技术下面这份清单专挑、且与“全双工语音对话/同步对话(边听边说、可打断、回馈/相槌、重叠语音)”直接相关的。我也结合你提到的的四大维度(暂停处理、相槌、顺滑换手、打断管理)来点出它们各自的贡献点,便于后续评测与对比。

u013250861的博客 630

线程池的两种关闭方式以及区别

  今天看书,看到线程池的关闭方式,记个笔记      线程池大家都知道,用来实现资源复用的。避免了线程频繁的创建和销毁的开销。待到使用完毕后都要关闭线程池,以释放资源。      线程池关闭后里面有任务正在工作的线程会怎么样      在树上有这么一段:   可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池。它们的原理是遍历线 程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务 可能永远无法终止。但是它们存在一定的区别,shutdown

秃头计划——启动! 3272

2026年全国青少年信息素养大赛算法应用主题赛(C++赛项初赛模拟卷1及答案解析)

2026年全国青少年信息素养大赛算法应用主题赛(C++赛项初赛模拟卷1及答案解析)

王老师青少年编程 2023

Spring环境中正确关闭线程池的姿势

前言 在Java System#exit 无法退出程序的问题探索一文末尾提到优雅停机的一种实现方案,要借助Shutdown Hook进行实现,本文,将继续探索优雅停机中遇到的一些问题:应用中线程池的优雅关闭 线程池正确关闭的姿势 在这一节,先不讨论应用中线程池该如何优雅关闭以达到优雅停机的效果,只是简单介绍一下线程池正确关闭的姿势 为简化讨论的复杂性,本文的线程池均是指JDK中的java.util.concurrent.ThreadPoolExecutor 正确关闭线程池的关键是 shutdown +

七夜 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java中如何正确的关闭线程池ExecutorService

概念 ExecutorService关于关闭主要有如下几个方法 shutdown:在线程池队列中的提交的任务会执行,无法提交新的任务,注意调用这个方法,线程池不会等待(wait)在执行的任务执行完成,可以使用awaitTermination实现这个目的。这里需要注意的是:在执行的任务因为是异步线程执行的,任务还是会继续执行,只是说线程池不会阻塞等待任务执行完成 List<Runnable&...

zlp1992的专栏 8903

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

java线程池shutdownnow后怎么再启动_线程池正确安全的关闭方式

上篇文章 ShutdownHook- Java 优雅停机解决方案 提到应用停机时需要释放资源,关闭连接。对于一些定时任务或者网络请求服务将会使用线程池,当应用停机时需要正确安全的关闭线程池,如果处理不当,可能造成数据丢失,业务请求结果不正确等问题。关闭线程池我们可以选择什么都不做,JVM 关闭时自然的会清除线程池对象。当然这么做,存在很大的弊端,线程池中正在执行执行的线程以及队列中还未执行任务将会...

weixin_39990250的博客 5013

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

你知道如何安全正确的关闭线程池吗?

我们知道应用停机时需要释放资源,关闭连接,而对于一些定时任务或者网络请求服务会使用线程池,当应用停机时我们需要正确安全的关闭线程池,如果处理不当,可能造成数据丢失,业务请...

Java极客技术 1401

还有任务没执行,线程池被关闭怎么办?

▌ThreadPoolExecutor 使用 runState (运行状态) 变量,管理线程池的生命周期,runState 一共有以下5种取值:(1)RUNNING:接收新的任务,并对任务队列里的任务进行处理;(2)SHUTDOWN:不再接收新的任务,但是会对任务队列中的任务进行处理;(3)STOP:不接收新任务,也不再对任务队列中的任务进行处理,并中断正在处理的任务;

harmful_sheep的博客 2162

如何正确的关闭线程池?

首先看源码中的一句注释: A pool that is no longer referenced in a program and has no remaining threads will be shutdown automatically. 如果程序中不再持有线程池的引用,并且线程池中没有线程时,线程池将会自动关闭。 线程池自动关闭的两个条件:1、线程池的引用不可达;2、线程池中没有...

z69183787的专栏 1234

14、java如何正确关闭线程池?

在掌握了这 5 种关闭线程池相关的方法之后,我们就可以根据自己的业务需要,选择合适的方法来停止线程池,比如通常我们可以用 shutdown() 方法来关闭,这样可以让已提交的任务都执行完毕,但是如果情况紧急,那我们就可以用 shutdownNow 方法来加快线程池“终结”的速度。正常停止线程的本质,是让线程任务的run方法执行完,对应到线程池的线程,就是Worker类的run方法执行完。这个run方法执行完的前提是getTask()返回的是null。

zht245648124的博客 1808

如何正确关闭线程池?

首先了解下ExecutorService接口中涉及线程池关闭的几个方法: /** *这个方法是一种安全关闭线程池的方法,调用这个方法后, *线程池会根据拒绝策略来拒绝新提交的任务, *然后线程池会把正在执行的任务,和在队列中等待任务都执行完后才会彻底关闭。 */ void shutdown(); /** *这个方法就比较强势了,调用...

硅脂味咖啡的博客 1718

【Java】创建线程池验证synchronized以及线程池关闭的正确姿势

talk is cheap,show methe code 这里创建了包含10个线程的线程池,每个线程池对变量做1000次自增 如果去掉synchronized,最后的结果就不是10000,因为自增操作不是原子性的 举个栗子: 假如某个时刻变量inc的值为10, 线程1对变量进行自增操作,线程1先读取了变量inc的原始值,然后线程1被阻塞了; 然后线程2对变量进行自增操作,线程2也...

ssjdoudou的博客 3388

java线程池的关闭

java关闭线程池的两种方式:手动和自动。

赶路人儿 5465
上一篇: Java 移位运算符
下一篇: Clickhouse 入门教程(一)—— 安装与启动
magicpenta
博客等级 码龄10年 42粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值