最近查看关于中断的文章,国内写的文章良莠不齐,我看了很多国内的文章写的很难理解,在阅读了Oracle的官方教程后我立刻理解了,于是想翻译出来,让更多人看到。
本文翻译自Oracle JavaSE Tutorial
https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
中断 (Interrupt)
中断给线程一个指示它应该停下当前的任务然后处理其他事物。线程如何响应一个中断,具体的方式取决于程序员,通常情况下我们使线程停止下来。接下来这篇教程阐述中断的使用。
一个线程调用被中断线程对象的interrupt方法来实现中断该线程。为了使中断机制正常执行,被中断线程必须自己实现对中断的处理
线程如何实现对中断信号的处理呢?这取决于它当前处理的任务。如果线程通常是通过抛出中断异常来实现对中断的处理,那么在捕获异常后直接在run()方法中return结束处理。比如,一个实现了Runnable接口的线程执行的是sleep操作,那么它可能通过如下操作来实现对中断的处理:
for (int i = 0; i < importantInfo.length; i++) {
// Pause for 4 seconds
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// We've been interrupted: no more messages.
return;
}
// Print a message
System.out.println(importantInfo[i]);
}
很多的方法抛出中断异常来处理中断,比如sleep方法,在收到中断后一般会结束当前任务然后立刻在run方法中return。如果线程很久都没有抛出中断异常我们应该怎么做呢?这个时候它应该定期的去调用Thread.interrupted来检测是否被中断,如果线程被中断Thread.interrupted会返回true,比如:
for (int i = 0; i < inputs.length; i++) {
heavyCrunch(inputs[i]);
if (Thread.interrupted()) {
// We've been interrupted: no more crunching.
return;
}
}
下面的代码就是用Thread.interrupted检测是否收到中断,如果收到就抛出一个新的中断异常。在更复杂的应用里,可能会做更多有实际意义的事。
if (Thread.interrupted()) {
throw new InterruptedException();
}
一般情况下,中断处理我们可以在catch块中实现。
中断机制的实现是通过使用一个内部标记flag来标识中断状态的。调用Thread.interrupt
会重置这个flag。
当线程使用静态方法Thread.interrupted检测到是中断时,会将flag的中断标记清除。一般非静态方法
isInterrupted方法被对象调用来检测另一个线程的中断状态,它不会改变这个线程的内部中断标记。
通常情况下,任何通过调用中断异常来结束中断处理的方法在执行完操作后都会消除内部的中断标记。
但是很有可能在标记被清除后立刻被其他线程调用中断方法,这个时候内部标记会重新被标记为中断。