Java 并发编程实战
王宝令
资深架构师
72486 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
学习攻略 (1讲)
Java 并发编程实战
15
15
1.0x
00:00/00:00
登录|注册

35 | 两阶段终止模式:如何优雅地终止线程?

使用自定义线程终止标志位
设置中断标志位
使用线程池时需要注意的事项
两阶段终止模式关键点
shutdownNow()方法
shutdown()方法
示例代码
动态采集功能示意图
设置终止标志位
interrupt()方法
Java线程状态转换图
两阶段终止模式示意图
stop()方法不建议使用
课后思考
总结
终止线程池
终止监控操作
终止线程
两阶段终止模式

该思维导图由 AI 生成,仅供参考

前面两篇文章我们讲述的内容,从纯技术的角度看,都是启动多线程去执行一个异步任务。既启动,那又该如何终止呢?今天咱们就从技术的角度聊聊如何优雅地终止线程,正所谓有始有终。
《09 | Java 线程(上):Java 线程的生命周期》中,我曾讲过:线程执行完或者出现异常就会进入终止状态。这样看,终止一个线程看上去很简单啊!一个线程执行完自己的任务,自己进入终止状态,这的确很简单。不过我们今天谈到的“优雅地终止线程”,不是自己终止自己,而是在一个线程 T1 中,终止线程 T2;这里所谓的“优雅”,指的是给 T2 一个机会料理后事,而不是被一剑封喉。
Java 语言的 Thread 类中曾经提供了一个 stop() 方法,用来终止线程,可是早已不建议使用了,原因是这个方法用的就是一剑封喉的做法,被终止的线程没有机会料理后事。
既然不建议使用 stop() 方法,那在 Java 领域,我们又该如何优雅地终止线程呢?

如何理解两阶段终止模式

前辈们经过认真对比分析,已经总结出了一套成熟的方案,叫做两阶段终止模式。顾名思义,就是将终止过程分成两个阶段,其中第一个阶段主要是线程 T1 向线程 T2发送终止指令,而第二阶段则是线程 T2响应终止指令
两阶段终止模式示意图
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了如何优雅地终止线程,重点介绍了两阶段终止模式。该模式将线程终止过程分成两个关键阶段,通过发送终止指令和响应指令来实现线程的安全终止。作者还提供了实际案例,展示了如何在监控操作中应用两阶段终止模式。此外,文章还讨论了线程池的优雅终止方法,详细介绍了shutdown()和shutdownNow()方法的区别及使用场景。总的来说,本文通过技术角度深入探讨了线程终止的优雅方式,为读者提供了实用的技术指导。在Java语言中使用两阶段终止模式来优雅地终止线程时,需要注意两个关键点:一个是仅检查终止标志位是不够的,另一个是仅检查线程的中断状态也是不够的。当使用Java的线程池来管理线程时,需要依赖线程池提供的shutdown()和shutdownNow()方法来终止线程池。不过在使用时需要注意它们的应用场景,尤其是在使用shutdownNow()的时候,一定要谨慎。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(62)

  • 最新
  • 精选
  • 佑儿
    stop和start方法对于terminated访问由于syn关键字,线程安全,但是start中新起了一个线程rptthread,导致stop方法中对于terminated存在可见性问题,因此需要volatie,原子性问题对这个代码段没有影响,所以原子性问题无需关注。

    作者回复: 👍

    2019-05-20
    4
    68
  • echo_陈
    我觉得,在本例子中。stop中,设置终止标识位对interupt是可见的。而interrupt对被中断线程检测到中断事件是可见的……根据传递性原则……我觉得本例子不需要volatile关键字。但平时开发中,一般会加上,主要是因为怕后续开发不注意这些事情导致修改破坏了规则,引起可见性问题产生bug,保险起见会加上volatile

    作者回复: 是的,线程不调用wait,sleep等方法,是无法响应中断的,这个时候基于interrupt的可见性就不成立了,所以工程上这类变量都需要加volatile

    2019-05-18
    12
    43
  • 遇见阳光
    按道理而言,synchronized保证原子性的同时,也能间接的保证可见性啊。感觉可以不加 volatile关键字

    作者回复: 问题是start方法里又启动了一个新的线程,synchronized管不到这个新的线程

    2019-05-18
    4
    29
  • 孙志强
    有必要,变量被多个线程访问,需要保证可见性

    作者回复: 👍

    2019-05-18
    3
    28
  • WL
    请问一下老师"JVM 的异常处理会清除线程的中断状态"指的是什么意思, 是指把线程的为true的中断状态改为false吗, JVM是在catch到Interrupt异常的时候重置线程中断状态的吗?

    作者回复: 是的

    2019-05-20
    16
  • 远东通信-应用软件
    在本章节后面一个实例代码中while循环没有使用线程的中断标志位做判断,但是stop里面仍然去调用rptThread.interrupt()有必要吗?只是为了将采集线程从sleep状态唤醒吗?

    作者回复: 是的

    2019-10-12
    2
    13
  • jason
    按这样说,新线程里会修改start变量的值,为了保证start的最新值能被start()方法看见,是不是也要对start变量加volatile修饰?

    作者回复: 加上更保险,不加数据也不会错,只是可能需要多等一会

    2020-01-11
    7
  • 青铜5 周群力
    什么情况需要手动shutdown线程池呢,我理解只要线程池不再被引用,里面的线程自己就被gc回收掉了,不需要手动调shutdown?

    作者回复: 基本上带池字的,生命周期都和应用同龄

    2020-05-05
    2
    6
  • 老师,想问一个问题如果interrupt()方法只是给线程打一个中断的标签,那么如果我线程本身没有显示的去做这个标的判断,线程还能被中断么,当然线程是runnable的,如果能中断又是谁去识别的呢?

    作者回复: 线程不能被中断,但是很多系统函数如sleep是响应中断的。极端地讲,纯CPU计算一定不会被中断

    2019-07-16
    2
    5
  • ban
    老师,思考题前的最后一个示例代码,为什么 // 线程终止标志位 volatile boolean terminated = false; boolean started = false; 为什么started可以不加volatile,terminated却要加呢?

    作者回复: started的读写都在同步方法里面

    2019-05-24
    5
收起评论
显示
设置
留言
62
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部