每一个线程都有一个boolean类型的中断状态。当中断线程时,这个线程的中断状态将被设置为true,在Thread中,有以下三个方法中断线程和查询线程中断状态的方法。
public class Tread{
public void interrupt(){....}
public boolean isInterrupted(){....}
public static boolean interrupted(){....}
}
interrupt方法将中断目标线程,而isInterrupted方法能返回目标线程的中断状态,interrupted将清除当前线程的中断状态,并返回它之前的值,也是清除中断状态的唯一方法。
阻塞库方法,例如Thread.sleep和Object.wait等,都会检查线程的中断状态,并且在发现中断时提前返回。他们在响应中断时的执行操作:清除中断状态,抛出InterruptedException,
表示阻塞操作由于中断而提前结束。
中断操作不会真正的中断一个正在运行的线程,而是发出中断请求。然后由线程在一个合适的时刻中断自己。(这个时刻也被称为取消点)。通常,中断是实现取消的最合理方式。
由于每一个线程拥有各自的中断策略,因此除非你知道中断对改线程的含义,否则就不应该中断这个线程。
当调用可中断的阻塞函数时,如BlockingQueu.put等,有两种实用策略可用于处理InterruptedException:
1.传递异常,从而使你的方法也成为可中断的阻塞方法。
2.恢复中断状态,从而使调用栈中的上层代码能够对其进行处理。
传递异常相对简单,如果不想传递异常或者无法传递InterruptedException(或许通过Runnable来定义任务),那么需要另一种方式来保存中断。一种标准方法就是通过再次调用interrupt来恢复中断状态。你不能屏蔽InterruptedException,例如在catch块中捕获到异常去不做任何处理,除非在你的代码中实现了线程的中断策略。
例如不可取消的任务在退去前恢复中断
public Task getNextTask(BlockingQueue<Task> queue){
boolean interrupted = false;
try{
while(true){
try {
return queue.take();
} catch (InterruptedException e) {
// try again
interrupted=true;
}
}
}finally{
if(interrupted){
Thread.currentThread().interrupt();
}
}
}
如果过早设置中断状态,就可能引起无限循环,因为大多数可中断的阻塞方法都会在入口处检查中断状态,并且当发现被设置时会立即抛出InterruptedException异常。(检查中断,从而尽快响应中断)