35 | 两阶段终止模式:如何优雅地终止线程?
王宝令
该思维导图由 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
《Java 并发编程实战》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(62)
- 最新
- 精选
- 佑儿stop和start方法对于terminated访问由于syn关键字,线程安全,但是start中新起了一个线程rptthread,导致stop方法中对于terminated存在可见性问题,因此需要volatie,原子性问题对这个代码段没有影响,所以原子性问题无需关注。
作者回复: 👍
2019-05-20468 - echo_陈我觉得,在本例子中。stop中,设置终止标识位对interupt是可见的。而interrupt对被中断线程检测到中断事件是可见的……根据传递性原则……我觉得本例子不需要volatile关键字。但平时开发中,一般会加上,主要是因为怕后续开发不注意这些事情导致修改破坏了规则,引起可见性问题产生bug,保险起见会加上volatile
作者回复: 是的,线程不调用wait,sleep等方法,是无法响应中断的,这个时候基于interrupt的可见性就不成立了,所以工程上这类变量都需要加volatile
2019-05-181243 - 遇见阳光按道理而言,synchronized保证原子性的同时,也能间接的保证可见性啊。感觉可以不加 volatile关键字
作者回复: 问题是start方法里又启动了一个新的线程,synchronized管不到这个新的线程
2019-05-18429 - 孙志强有必要,变量被多个线程访问,需要保证可见性
作者回复: 👍
2019-05-18328 - WL请问一下老师"JVM 的异常处理会清除线程的中断状态"指的是什么意思, 是指把线程的为true的中断状态改为false吗, JVM是在catch到Interrupt异常的时候重置线程中断状态的吗?
作者回复: 是的
2019-05-2016 - 远东通信-应用软件在本章节后面一个实例代码中while循环没有使用线程的中断标志位做判断,但是stop里面仍然去调用rptThread.interrupt()有必要吗?只是为了将采集线程从sleep状态唤醒吗?
作者回复: 是的
2019-10-12213 - jason按这样说,新线程里会修改start变量的值,为了保证start的最新值能被start()方法看见,是不是也要对start变量加volatile修饰?
作者回复: 加上更保险,不加数据也不会错,只是可能需要多等一会
2020-01-117 - 青铜5 周群力什么情况需要手动shutdown线程池呢,我理解只要线程池不再被引用,里面的线程自己就被gc回收掉了,不需要手动调shutdown?
作者回复: 基本上带池字的,生命周期都和应用同龄
2020-05-0526 - 其老师,想问一个问题如果interrupt()方法只是给线程打一个中断的标签,那么如果我线程本身没有显示的去做这个标的判断,线程还能被中断么,当然线程是runnable的,如果能中断又是谁去识别的呢?
作者回复: 线程不能被中断,但是很多系统函数如sleep是响应中断的。极端地讲,纯CPU计算一定不会被中断
2019-07-1625 - ban老师,思考题前的最后一个示例代码,为什么 // 线程终止标志位 volatile boolean terminated = false; boolean started = false; 为什么started可以不加volatile,terminated却要加呢?
作者回复: started的读写都在同步方法里面
2019-05-245
收起评论