Welcome 微信登录

首页 / 软件开发 / JAVA / Java中断机制详解

Java中断机制详解2013-09-14 丁一 1. 引言

当我们点击某个杀毒软件的取消按钮来停止查杀病毒时,当我们在控制台敲入quit命令以结束某个后台 服务时……都需要通过一个线程去取消另一个线程正在执行的任务。Java没有提供一种安全直接的方法来停止某个线程,但 是Java提供了中断机制。

如果对Java中断没有一个全面的了解,可能会误以为被中断的线程将立马退出运行,但事 实并非如此。中断机制是如何工作的?捕获或检测到中断后,是抛出InterruptedException还是重设中断状态以及在方法中 吞掉中断状态会有什么后果?Thread.stop与中断相比又有哪些异同?什么情况下需要使用中断?本文将从以上几个方面进 行描述。

2. 中断的原理

Java中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而 需要被中断的线程自己处理中断。这好比是家里的父母叮嘱在外的子女要注意身体,但子女是否注意身体,怎么注意身体则 完全取决于自己。

Java中断模型也是这么简单,每个线程对象里都有一个boolean类型的标识(不一定就要是Thread 类的字段,实际上也的确不是,这几个方法最终都是通过native方法来完成的),代表着是否有中断请求(该请求可以来自 所有线程,包括被中断的线程本身)。例如,当线程t1想中断线程t2,只需要在线程t1中将线程t2对象的中断标识置为true ,然后线程2可以选择在合适的时候处理该中断请求,甚至可以不理会该请求,就像这个线程没有被中断一样。

java.lang.Thread类提供了几个方法来操作这个中断状态,这些方法包括:

public static boolean interrupted
 
测试当前线程是否已经中断。线程的中断 状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中 断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
 
public boolean isInterrupted()
 
测试线程 是否已经中断。线程的中断状态不受该方法的影响。
 
public void interrupt()
 
中断线程。
 
 

其中,interrupt方法是唯一能将中断状态设置为true的方法。静态方法 interrupted会将当前线程的中断状态清除,但这个方法的命名极不直观,很容易造成误解,需要特别注意。

上面的 例子中,线程t1通过调用interrupt方法将线程t2的中断状态置为true,t2可以在合适的时候调用interrupted或 isInterrupted来检测状态并做相应的处理。

此外,类库中的有些类的方法也可能会调用中断,如FutureTask中的 cancel方法,如果传入的参数为true,它将会在正在运行异步任务的线程上调用interrupt方法,如果正在执行的异步任务 中的代码没有对中断做出响应,那么cancel方法中的参数将不会起到什么效果;又如ThreadPoolExecutor中的shutdownNow 方法会遍历线程池中的工作线程并调用线程的interrupt方法来中断线程,所以如果工作线程中正在执行的任务没有对中断 做出响应,任务将一直执行直到正常结束。

3. 中断的处理

既然Java中断机制只是设置被中断线程的中断状 态,那么被中断线程该做些什么?

处理时机

显然,作为一种协作机制,不会强求被中断 线程一定要在某个点进行处理。实际上,被中断线程只需在合适的时候处理即可,如果没有合适的时间点,甚至可以不处理 ,这时候在任务处理层面,就跟没有调用中断方法一样。“合适的时候”与线程正在处理的业务逻辑紧密相关,例如,每次 迭代的时候,进入一个可能阻塞且无法中断的方法之前等,但多半不会出现在某个临界区更新另一个对象状态的时候,因为 这可能会导致对象处于不一致状态。

处理时机决定着程序的效率与中断响应的灵敏性。频繁的检查中断状态可能会 使程序执行效率下降,相反,检查的较少可能使中断请求得不到及时响应。如果发出中断请求之后,被中断的线程继续执行 一段时间不会给系统带来灾难,那么就可以将中断处理放到方便检查中断,同时又能从一定程度上保证响应灵敏度的地方。 当程序的性能指标比较关键时,可能需要建立一个测试模型来分析最佳的中断检测点,以平衡性能和响应灵敏性。