取消/关闭的机制
Java的Thread类定义了如下方法:
public final void stop()
这个方法看上去就可以停止线程,但这个方法被标记为了过时,简单地说,我们不应该使用它,可以忽略它。
如果强制 杀死线程,则线程中所使用的资源,例如文件描述符、网络连接等不 能正常关闭。 因此,一个线程一旦运行起来,就不要去强行打断它,合理的关 闭办法是让其运行完(也就是函数执行完毕),干净地释放掉所有资 源,然后退出。如果是一个不断循环运行的线程,就需要用到线程间 的通信机制,让主线程通知其退出。
线程的中断
在Java中,停止一个线程的主要机制是中断,中断并不是强迫终止一个线程,它是一种协作机制,是给线程传递一个取消信号,但是由线程来决定如何以及何时退出。
Thread类定义了如下关于中断的方法:
public boolean isInterrupted() public void interrupt() public static boolean interrupted()
isInterrupted()和interrupt()是实例方法,调用它们需要通过线程对象;
interrupted()是静态方法,实际会调用Thread. currentThread()操作当前线程。
每个线程都有一个标志位,表示该线程是否被中断了。
1)isInterrupted:返回对应线程的中断标志位是否为true。
2)interrupted:返回当前线程的中断标志位是否为true,但它还有一个重要的副作用,就是清空中断标志位,也就是说,连续两次调用interrupted(),第一次返回的结果为true,第二次一般就是false(除非同时又发生了一次中断)。
3)interrupt:设置中断标志为true。
轻量级阻塞与重量级阻塞
能够被中断的阻塞称为轻量级阻塞,对应的线程状态是WAITING或 者TIMED_WAITING;而像 synchronized 这种不能被中断的阻塞称为重量级阻塞,对应的状态是 BLOCKED。
线程对中断的反应
- RUNNABLE interrupt()会设置线程的中断标志位
- WAITING/TIMED_WAITING interrupt()会使得该线程抛出InterruptedException。需要注意的是,抛出异常后,中断标志位会被清空,而不是被设置。
- BLOCKED interrupt()会设置线程的中断标志位,线程依然会处于BLOCKED状态,也就是说,interrupt()并不能使一个在等待锁的线程真正“中断”。
- NEW/TERMINATE 如果线程尚未启动(NEW),或者已经结束(TERMINATED),则调用interrupt()对它没有任何效果,中断标志位也不会被设置。
如何正确地取消/关闭线程
interrupt方法不一定会真正“中断”线程,它只是一种协作机制,如果不明白线程在做什么,不应该贸然地调用线程的interrupt方法,以为这样就能取消线程。
对于以线程提供服务的程序模块而言,它应该封装取消/关闭操作,提供单独的取消/关闭方法给调用者,外部调用者应该调用这些方法而不是直接调用interrupt。
参考: Java编程的逻辑 15.4 线程的中断
Java并发实现原理:JDK源码剖析 1.2 InterruptedException()函数与 interrupt()函数