0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何正确关闭线程池

Android编程精选 来源:CSDN博客 作者:不懂的浪漫 2021-09-29 14:41 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

前言本章分为两个议题

如何正确关闭线程池

shutdown 和 shutdownNow 的区别

项目环境jdk 1.8

github 地址:https://github.com/huajiexiewenfeng/java-concurrent

本章模块:threadpool

1.线程池示例

public class ShutDownThreadPoolDemo {

private ExecutorService service = Executors.newFixedThreadPool(10);

public static void main(String[] args) {

new ShutDownThreadPoolDemo().executeTask();

}

public void executeTask() {

for (int i = 0; i 《 100; i++) {

service.submit(() -》 {

System.out.println(Thread.currentThread().getName() + “-》执行”);

});

}

}

}

执行结果

pool-1-thread-2-》执行

pool-1-thread-3-》执行

pool-1-thread-1-》执行

pool-1-thread-4-》执行

pool-1-thread-5-》执行

pool-1-thread-6-》执行

。..

执行完成之后,主线程会一直阻塞,那么如何关闭线程池呢?本章介绍 5 种在 ThreadPoolExecutor 中涉及关闭线程池的方法,如下所示

void shutdown

boolean isShutdown

boolean isTerminated

boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException

List《Runnable》 shutdownNow

2.shutdown

第一种方法叫作 shutdown(),它可以安全地关闭一个线程池,调用 shutdown() 方法之后线程池并不是立刻就被关闭,因为这时线程池中可能还有很多任务正在被执行,或是任务队列中有大量正在等待被执行的任务,调用 shutdown() 方法后线程池会在执行完正在执行的任务和队列中等待的任务后才彻底关闭。

调用 shutdown() 方法后如果还有新的任务被提交,线程池则会根据拒绝策略直接拒绝后续新提交的任务。学习资料:Java进阶视频资源

这段源码位置(jdk 1.8 版本)

java.util.concurrent.ThreadPoolExecutor#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);

else if (workerCountOf(recheck) == 0)

// 如果之前的线程已经被销毁完,新建一个非核心线程

addWorker(null, false);

}

// 核心线程池已满,队列已满,尝试创建一个非核心新的线程

else if (!addWorker(command, false))

// 如果创建新线程失败,说明线程池关闭或者线程池满了,拒绝任务

reject(command);

}

1373 行 if (! isRunning(recheck) && remove(command))如果线程池被关闭,将当前的任务从任务队列中移除成功,并拒绝该任务

1378 行 else if (!addWorker(command, false))如果创建新线程失败,说明线程池关闭或者线程池满了,拒绝任务。

3.isShutdown

第二个方法叫作 isShutdown(),它可以返回 true 或者 false 来判断线程池是否已经开始了关闭工作,也就是是否执行了 shutdown 或者 shutdownNow 方法。

这里需要注意,如果调用 isShutdown() 方法的返回的结果为 true 并不代表线程池此时已经彻底关闭了,这仅仅代表线程池开始了关闭的流程,也就是说,此时可能线程池中依然有线程在执行任务,队列里也可能有等待被执行的任务。

4.isTerminated

第三种方法叫作 isTerminated(),这个方法可以检测线程池是否真正“终结”了,这不仅代表线程池已关闭,同时代表线程池中的所有任务都已经都执行完毕了。

比如我们上面提到的情况,如果此时已经调用了 shutdown 方法,但是还有任务没有执行完,那么此时调用 isShutdown 方法返回的是 true,而 isTerminated 方法则会返回 false。

直到所有任务都执行完毕了,调用 isTerminated() 方法才会返回 true,这表示线程池已关闭并且线程池内部是空的,所有剩余的任务都执行完毕了。

学习资料:Java进阶视频资源

5.awaitTermination

第四个方法叫作 awaitTermination(),它本身并不是用来关闭线程池的,而是主要用来判断线程池状态的。

比如我们给 awaitTermination 方法传入的参数是 10 秒,那么它就会陷入 10 秒钟的等待,直到发生以下三种情况之一:

等待期间(包括进入等待状态之前)线程池已关闭并且所有已提交的任务(包括正在执行的和队列中等待的)都执行完毕,相当于线程池已经“终结”了,方法便会返回 true

等待超时时间到后,第一种线程池“终结”的情况始终未发生,方法返回 false

等待期间线程被中断,方法会抛出 InterruptedException 异常

调用 awaitTermination 方法后当前线程会尝试等待一段指定的时间,如果在等待时间内,线程池已关闭并且内部的任务都执行完毕了,也就是说线程池真正“终结”了,那么方法就返回 true,否则超时返回 fasle。

6.shutdownNow

最后一个方法是 shutdownNow(),它和 shutdown() 的区别就是多了一个 Now,表示立刻关闭的意思,不推荐使用这一种方式关闭线程池。

在执行 shutdownNow 方法之后,首先会给所有线程池中的线程发送 interrupt 中断信号,尝试中断这些任务的执行,然后会将任务队列中正在等待的所有任务转移到一个 List 中并返回,我们可以根据返回的任务 List 来进行一些补救的操作,例如记录在案并在后期重试。

shutdownNow 源码如下:

public List《Runnable》 shutdownNow() {

List《Runnable》 tasks;

final ReentrantLock mainLock = this.mainLock;

mainLock.lock();

try {

checkShutdownAccess();

advanceRunState(STOP);

interruptWorkers();

tasks = drainQueue();

} finally {

mainLock.unlock();

}

tryTerminate();

return tasks;

}

interruptWorkers

让每一个已经启动的线程都中断,这样线程就可以在执行任务期间检测到中断信号并进行相应的处理,提前结束任务

7.shutdown 和 shutdownNow 的区别?

shutdown 会等待线程池中的任务执行完成之后关闭线程池,而 shutdownNow 会给所有线程发送中断信号,中断任务执行,然后关闭线程池

shutdown 没有返回值,而 shutdownNow 会返回关闭前任务队列中未执行的任务集合(List)

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 模块
    +关注

    关注

    7

    文章

    2849

    浏览量

    53456
  • 多线程
    +关注

    关注

    0

    文章

    279

    浏览量

    21132

原文标题:正确关闭线程池:shutdown 和 shutdownNow 的区别

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    天合光能联合共建中国首个光伏产业专利

    4月21日下午,在工业和信息化部、国家知识产权局联合指导下,由中国光伏行业协会知识产权专业委员会、国家光伏制造产业知识产权运营中心共同主办的光伏专利专家指导委员会成立仪式暨光伏专利共建研讨会在北京举行,会上正式启动中国光伏行业首个专利
    的头像 发表于 04-24 15:18 809次阅读

    生产环境数据库连接耗尽的全流程排查与性能优化实战

    数据库连接是应用程序与数据库之间的缓存连接组件。连接在应用程序启动时创建一组数据库连接,应用程序从连接获取连接,使用完毕后归还连接而非关闭
    的头像 发表于 03-27 15:58 336次阅读

    解析Linux的进程、线程和协程

    系统的稳定性和安全性。 (3)创建与销毁:Linux使用fork()系统调用来创建新进程,通过exit()来终止进程。 线程(Thread) 线程是进程内的执行单元,多个线程共享相同的内存空间
    发表于 12-22 11:00

    开放协作,共筑生态——思尔芯参与上海开放处理器产业创新中心开业仪式暨RISC-V专利联盟专利仪式

    在推动芯片产业自主创新、构建开放协作生态的背景下,上海开放处理器产业创新中心(SOPIC)于2025年12月12日在上海张江正式举办开业仪式。同期举行的RISC-V专利仪式上,思尔芯作为首批入
    的头像 发表于 12-15 17:38 1315次阅读
    开放协作,共筑生态——思尔芯参与上海开放处理器产业创新中心开业仪式暨RISC-V专利联盟专利<b class='flag-5'>池</b>入<b class='flag-5'>池</b>仪式

    C语言内存使用

    ,整个堆有可能被弄得支离破碎,最终导致大量内存浪费。 那么这种情况下,我们解决这类问题的思路,就是创建一个内存。 内存,实际上就是我们让程序创建出来的一块额外的缓存区域,如果有需要释放内存,先
    发表于 12-11 07:57

    线程的系统

    线程系统的事件响应也是在中断中完成的,但事件的处理是在线程中完成的。在多线程系统中,线程跟中断一样,也具有优先级,优先级高的线程会被优先执
    发表于 12-08 07:55

    Linux多线程对比单线程的优势

    在Linux系统中,线程是操作系统能够进行运算调度的最小单位。线程被包含在进程之中,是进程中的实际运行单位。一个进程可以拥有多个线程,这些线程共享相同的内存空间和系统资源。
    发表于 12-01 06:11

    数据全复用高性能化层设计思路分享

    大家好,本团队此次分享的内容为可实现数据全复用高性能化层设计思路,核心部分主要由以下3个部分组成; 1.SRAM读取模块;——化使用的存储为SRAM 基于SRAM读与写时序,约束化模块读与写
    发表于 10-29 07:10

    线程问题,线程已经创建成功了,为什么线程调用的函数不会运行呢?

    我这个线程创建成功了,为啥ai_thread_entry()函数不运行呢? void airun_thread() { /* 创建 serial 线程 */ rt_thread_t
    发表于 10-10 08:02

    tcpip线程被mu0锁住导致网络线程无法使用怎么解决?

    各位好,我使用rtthread开发STM32F407VGT6芯片,程序有多个线程,每个线程都会创建一个socket,建立tcp连接或者udp连接,现在出现一个问题,程序长时间运行有概率死机,但是没有
    发表于 09-29 06:41

    启用了控制台后,空闲线程是不是永远不会进入?

    在控制台里打印线程(list thread)时,发现已经退出的线程已经是CLOSE状态,但是都是僵尸线程。然后查看shell代码,看到控制台一直在跑,所以手动添加了延时(rt_thread_delay)进入,但调试看到空闲
    发表于 09-19 06:53

    线程超时函数中 assert 失败是什么原因导致的?

    最近调试 gd32h759 遇到了一个十分奇怪的问题,在初步调通所有的逻辑功能后,发现系统经常会在运行一段时间后死在一个奇怪的线程超时函数中 assert 失败导致卡死。用 cmbacktrace
    发表于 09-09 06:56

    线程的安全注意事项

    线程安全是指多个线程同时访问或修改共享资源时,能够保证程序的正确性和可靠性。 开发者选择TaskPool或Worker进行多线程开发时,在TaskPool和Worker的工作
    发表于 06-20 07:49

    鸿蒙5开发宝藏案例分享---应用并发设计

    线程 --> |系统托管| FFRT_I/O[FFRT I/O线程] 三大核心理念 : 内存隔离 :线程间禁止直接共享对象 异步
    发表于 06-12 16:19

    对于配置为Source的CCG3PA应用,完全关闭输出的正确方法应该是什么?

    你好对于配置为 Source 的 CCG3PA 应用,支持 EVAL_HB_BC_1EDN7550B 1.2、USB-PD (+PPS) 和 Type-C,完全关闭输出的正确方法应该是什么,并在以后
    发表于 05-27 06:23