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

    文章

    2654

    浏览量

    47282
  • 多线程
    +关注

    关注

    0

    文章

    277

    浏览量

    19892

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

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

收藏 人收藏

    评论

    相关推荐

    买药秒送 JADE动态线程实践及原理浅析

    一、背景及JADE介绍 买药秒送是健康即时零售业务新的核心流量场域,面对京东首页高流量曝光,我们对频道页整个技术架构方案进行升级,保障接口高性能、系统高可用。 动态线程是买药频道应用的技术之一
    的头像 发表于 09-04 11:11 771次阅读
    买药秒送 JADE动态<b class='flag-5'>线程</b><b class='flag-5'>池</b>实践及原理浅析

    动态线程思想学习及实践

    相关文档 美团线程实践:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html 线程思想解
    的头像 发表于 06-13 15:43 1116次阅读
    动态<b class='flag-5'>线程</b><b class='flag-5'>池</b>思想学习及实践

    什么是动态线程?动态线程的简单实现思路

    因此,动态可监控线程一种针对以上痛点开发的线程管理工具。主要可实现功能有:提供对 Spring 应用内线程
    的头像 发表于 02-28 10:42 560次阅读

    线程的创建方式有几种

    线程是一种用于管理和调度线程的技术,能够有效地提高系统的性能和资源利用率。它通过预先创建一组线程并维护一个工作队列,将任务提交给线程
    的头像 发表于 12-04 16:52 795次阅读

    线程七大核心参数执行顺序

    线程是一种用于管理和调度线程执行的技术,通过将任务分配到线程池中的线程进行处理,可以有效地控制并发线程
    的头像 发表于 12-04 16:45 909次阅读

    核心线程数和最大线程数怎么设置

    。 一、核心线程数和最大线程数的定义与作用 核心线程数(Core Pool Size):指线程池中可以同时运行的线程的最小数量。即使提交更多
    的头像 发表于 12-01 13:50 8424次阅读

    线程三大核心参数的含义 线程核心线程数制定策略

    以上考点作为线程面试几乎必问的内容,大部分人应该都是如数家珍,张口就来,但是懂了面试八股文真的就不一定在实际运用中真的就会把线程用好 。
    的头像 发表于 12-01 10:20 958次阅读
    <b class='flag-5'>线程</b><b class='flag-5'>池</b>三大核心参数的含义 <b class='flag-5'>线程</b><b class='flag-5'>池</b>核心<b class='flag-5'>线程</b>数制定策略

    线程的运转流程图 化技术实践案例解析

    作为一名Java开发人员,化技术或多或少在业务代码中使用。常见的包括线程、连接等。也是因为Java语言超级丰富的基建,基本上这些化能
    的头像 发表于 11-24 10:22 419次阅读
    <b class='flag-5'>线程</b><b class='flag-5'>池</b>的运转流程图 <b class='flag-5'>池</b>化技术实践案例解析

    JDK如何优雅退出一个线程

    需要线程退出的常见场景 任务执行完成,或异常终止,任务认为无需再占用线程线程根据当前任务执行情况,伸缩线程
    的头像 发表于 11-17 10:02 402次阅读
    JDK如何优雅退出一个<b class='flag-5'>线程</b>?

    基于C++11的线程实现

    C++11 加入了线程库,从此告别了标准库不支持并发的历史。然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程、信号量等。
    的头像 发表于 11-13 15:29 700次阅读

    如何用C语言实现线程

    线程是一种多线程处理形式,大多用于高并发服务器上,它能合理有效的利用高并发服务器上的线程资源;线程与进程用于处理各项分支子功能,我们通常的
    的头像 发表于 11-13 10:41 964次阅读
    如何用C语言实现<b class='flag-5'>线程</b><b class='flag-5'>池</b>

    线程的基本概念

    线程的基本概念 不管线程是什么东西!但是我们必须知道线程被搞出来的目的就是:提高程序执行效
    的头像 发表于 11-10 16:37 481次阅读
    <b class='flag-5'>线程</b><b class='flag-5'>池</b>的基本概念

    线程基本概念与原理

    一、线程基本概念与原理 1.1 线程概念及优势 C++线程简介
    的头像 发表于 11-10 10:24 462次阅读

    了解连接线程、内存、异步请求

    可被重复使用像常见的线程、内存、连接、对象都具有以上的共同特点。 连接 什么是数据库连
    的头像 发表于 11-09 14:44 1125次阅读
    了解连接<b class='flag-5'>池</b>、<b class='flag-5'>线程</b><b class='flag-5'>池</b>、内存<b class='flag-5'>池</b>、异步请求<b class='flag-5'>池</b>

    什么是内存

    使用时就会变得非常快 捷,大大提高程序运行效率。 在计算机中,有很多使用“”这种技术的地方,除了内存,还有连接线程、对象
    的头像 发表于 11-08 16:26 810次阅读
    什么是内存<b class='flag-5'>池</b>