为了使任务和线程更加安全、快速、可靠地停止下来,因此Java没有提供任何机制来安全地终止线程,但它提供了中断机制,这是一种协作机制(因为任务本身地代码比发布取消请求的代码更清楚如何执行清除工作)。
其实 " 目标线程.interrupt() " 只是设置一个表达中断语义的标志位而已…
1. 任务取消常见的取消操作的场景:
用户通过图形化界面,调用接口发出“取消请求”。
有限时间的操作:计时器超时、在有限时间内求最优解。
针对某个问题空间进行分解并搜索,当其中一个任务找到解决方案时,其他的任务都可以被取消。
错误:当爬虫程序发生错误(磁盘满了),那么所有搜索任务都会被取消,并且记下当前状态,方便稍后重新启动。
服务关闭:略
使用BQ的时候,如果生产速度超过消费速度,那么可能导致put被队列阻塞。这时候,调用其cancel()来设置cancelled标志,可能导致生产者永远无法检查到这个请求(因此消费者已经被中断了,那么put将永远被阻塞下去)。
有一些特殊的阻塞库的一些方法支持中断,例如Thread.sleep()、Object.wait()等,都会检查线程何时中断,并在发现中断时提前返回。它们响应中断的方式包括:清除中断状态、抛出InterruptException。JVM并不能保证阻塞方法检测到中断的速度,但实际上响应中断的速度还是非常快的。
当线程在非阻塞状态下中断时,它的中断状态将被设置,然后根据将被取消的操作来检查中断状态以判断发生了中断。通过这种方法,中断操作将变得“有黏性”——如果不触发InterruptException,那么中断状态并一直保持,直到明确地清楚中断状态。这也促成了interrupt()的调用不会立马中断目标线程,而是传递了取消执行的请求,直至目标线程准备好了再自我中断。
在Java的API或语言规范中,并没有将中断与任何取消语义关联起来,但实际上,如果在取消之外使用中断,那么都是不合适的,并且很难支撑起更大的应用。
粗略的扯一下中断策略的设计思路:
像sleep()、wait()、join(),当它们收到中断请求或者开始执行的时候发现某个已经设置好的中断状态时,将严格处理(抛出IE)。设计良好的方法只要能够调用代码对中断进行处理,就可以完全忽略这种请求;设计糟糕的方法将直接屏蔽中断请求,导致调用栈上的其他方法无法对其做出响应。
可以通过while(xxx.isInterrupted())来提高中断的响应度。
1.2 中断策略因为大多数任务都不会在自己拥有的线程中执行,而是在某个服务(例如:线程池)拥有的线程中执行,对于非线程所有者的代码来说,最合理的中断策略:尽快退出,在必要的时候进行清理,通知某个所有者该线程已经退出,尽快的通知调用栈的上层代码以使其可以采取响应措施。此外还有一些其他的策略:暂停服务、重启服务。
粗略的扯一下中断响应的思路:
除了抛出IE,还可以先捕获IE之后再恢复中断。
正如任务代码不应该对其执行所在线程的中断策略做出假设,执行取消操作的代码也不应该对线程的中断策略做出假设。线程应该只能由其所有者中断,所有者可以将线程的中断策略信息封装到某个合适的取消机制中,例如关闭(shutdown)方法。



