https://github.com/javastacks/spring-boot-best-practice优雅关闭Or强行关闭
Thread.stop() 这种方法本身就是不安全的,Stop一个线程会随之解锁这个线程所持有的监视器(可以理解为锁),如果受这些监视器(锁)保护的临界对象处在不一致状态,则其他线程可能会看到这些对象处于不一致状态,那么将导致未知的行为。对Thread.Stop()的调用应该被简单的代码代替,例如 修改一个变量,目标线程定期检查这个变量,有序从run 方法return出来。如果目标线程在一个条件变量上wait,则其他线程应该使用interrupt方法中断目标线程。实际上关闭一个线程强行和通知是两种理念,即是否应该相信线程任务的开发者优雅的、快速的主动退出线程,而不是被其他线程强制终止。在Java中,退出线程的方式只有一种推荐,即优雅退出,并且jdk也给了建议,通过修改变量,由目标线程定期检查状态。或者通过interrupt中断方式通知目标线程。
JDK: 如果目标线程在一个条件变量上wait,则其他线程应该使用interrupt方法中断目标线程。interrupt的JDK注释提到,
如果其他线程调用目标线程的interrupt方法,线程中断位标记了当前线程是否处于被中断状态,并且提供了Thread.isInterrupted方法查看当前是否处于中断位?那为什么目标线程阻塞在Object.wait(),Sleep()方法时,抛出了interruptException,会取消标记呢?实际上interrupt操作执行两件事,1)设置中断位标记 2)通过unpark唤醒目标线程。(park和unpark分别可以阻塞线程和唤醒线程)
- 恰好目标线程在调用. Object.wait(),object.join(),Object.sleep()等方法时,目标线程的中断位标记被清除,同时目标线程会立即从sleep、wait等调用中恢复,并且被抛出InterruptException。
- 如果目标线程在IO操作中被阻塞,例如io.channels.InterruptibleChannel,Channel将被关闭,线程的中断位被设置,同时目标线程收到java.nio.channels.ClosedByInterruptException。
- 如果目标线程被阻塞在java.nio.channels.Selector,线程中断状态被设置,然后目标线程立即从select中返回非零值。
- 如果其他条件都不成立,该线程中断位会被设置。
推荐一个非常好的博客 通过JVM源码分析 interrupt和sleep的实现原理。然而目标线程醒来时会检查当前是否处于中断位,如果是sleep或者wait操作。如果处于中断位则取消中断位,抛出异常。取消中段位的原因应该是一种规范,即抛出中断异常,即通知了线程中断,无需再用中段位标记。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |