一直以来,用过很多线程的应用,最经常使用的就是开启一个线程,然后就不管之,任其运行。或者运行成功,或者运行失败,都跟主线程无关。稍微用得多一点的就是使用对象的wait,再配合线程之间的调度,当线程需要中断时,直接中断其,然后被中断的线程抛出一个中断异常,自然地被中止运行了(因为没有捕获异常,被中断线程方法自然停止运行)。
但是长久地来看,并没有了解线程中断的实质。从简单上来讲,中断一个线程,可以理解为中断这个线程的运行,就像使用thread.stop方法所运行的一样;并且实际运行效果也是这样,因为线程抛出了异常,而我们没捕获,则线程自然被中断,听起来中断一个线程就和停止线程运行一个效果。但实际上,这是两个完全不一样的工作方式。
所谓的线程停止,是指这个线程已经不再运行了;而中断,则是指线程由于某种原因被外力(或自身)要求停止不再运行,但线程仍然拥有是否继续运行(或停止运行)的权利,关键在于线程如何处理这个中断的动作。简单一点理解就是,线程中断,只是向线程发送了一个标记,表示这个线程应该中断了,但如何停止运行是由线程自身或处理中断的行为所决定的。
以下为引用内容:
JVM内部确实为每个线程维护了一个中断标记。
通常情况下,调用线程的interrupt方法,并不能立即引发中断,只是设置了JVM内部的中断标记。因此,通过检查中断标记,应用程序可以做一些特殊操作,也可以完全忽略中断。
你可能想,如果JVM只提供了这种简陋的中断机制,那和应用程序自己定义中断变量并轮询的方法相比,基本也没有什么优势。
JVM内部中断变量的主要优势,就是对于某些情况,提供了模拟自动“中断陷入”的机制。
在执行涉及线程调度的阻塞调用时(例如wait、sleep和join),如果发生中断,被阻塞线程会“尽可能快的”抛出InterruptedException。
所谓“尽可能快”,我猜测JVM就是在线程调度调度的间隙检查中断变量,速度取决于JVM的实现和硬件的性能。
另外,有jdk源代码为证,下方法为thread的interrupt方法:
所以,线程中断就是为指定的线程设定一个中断变量,然后当被操作的线程接收到这个变量之后,就努力地抛出一个中断异常出来。由于在一般情况下,我们没有catch这个异常,所以,线程被自然地异常退出了,而且不会影响到主线程。
在正式地线程调试中,肯定需要对线程的中断行为,定制不同的处理方式,比如安全地释放资源,然后安全的退出等。
既然有了这个中断的标记,那么肯定有读取这个标记的相应方法,即以下几个方法:
这上面的几个方法,有读取中断标记的,有读取中断标记并清除标记的,也有再次设置中断标记的。
在一个线程在运行当中时(特别是在线程内部),我们可以通过isInterrupted方法,查询这个线程是否已经被中断了。如果被中断了,则可以进行相应的操作。
当一个中断异常,抛出之后,它的中断标记即已经被清除,所以如果我们调用普通的isInterrupted方法时,将返回false。如果需要让上层的处理器知道此线程已经被中断了,我们需要再次调用interrupt方法来设置中断状态,并再次往上层抛出中断异常即可。
总结:线程的中断本质就是一个中断标记和中断异常的配合,当设置中断标记时,异常被抛出。如果未捕获异常,线程被以异常的方式结束运行。如果捕获异常,则按照具体的情况决定如何运行线程(是结束还是结束)。异常是天生的以另一种方式结束程序的方式,而中断标记则有效地利用了这一点,并且从程序运行层面欺骗了使用它的人。