interrupt() 它基于「一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。」思想,是一个比较温柔的做法,它更类似一个标志位。其实作用不是中断线程,而是「通知线程应该中断了」,具体到底中断还是继续运行,应该由被通知的线程自己处理。
interrupt() 并不能真正的中断线程,这点要谨记。需要被调用的线程自己进行配合才行。也就是说,一个线程如果有被中断的需求,那么就需要这样做:
- 在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程。
- 在调用阻塞方法时正确处理InterruptedException异常。(例如:catch异常后就结束线程。)
首先讲 interrupt() 方法:
- interrupt 中断操作时,非自身打断需要先检测是否有中断权限,这由jvm的安全机制配置;
- 如果线程处于sleep, wait, join 等状态,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常;
- 如果线程处于I/O阻塞状态,将会抛出ClosedByInterruptException(IOException的子类)异常;
- 如果线程在Selector上被阻塞,select方法将立即返回;
- 如果非以上情况,将直接标记 interrupt 状态;
注意:interrupt 操作不会打断所有阻塞,只有上述阻塞情况才在jvm的打断范围内,如处于锁阻塞的线程,不会受 interrupt 中断;
阻塞情况下中断,抛出异常后线程恢复非中断状态,即 interrupted = false
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Task("1"));
t.start();
t.interrupt();
}
static class Task implements Runnable{
String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("thread has been interrupt!");
}
System.out.println("isInterrupted: " + Thread.currentThread().isInterrupted());
System.out.println("task " + name + " is over");
}
}
}
结果:
thread has been interrupt! isInterrupted: false task 1 is over
上述两种隐含的状态恢复操作,是符合常理的,因为线程标记为中断后,用户没有真正中断线程,必然将其恢复为false。理论上Thread.interrupted()调用后,如果已中断,应该执行退出操作,不会重复调用。
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Task("1"));
t.start();
t.interrupt();
}
static class Task implements Runnable{
String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("first :" + Thread.interrupted());
System.out.println("second:" + Thread.interrupted());
System.out.println("task " + name + " is over");
}
}
}