结论
- Thread.interrupt()方法不会中断一个正在运行的线程,只是设置了中断状态,线程内部可以监听isInterrupted方法响应终止,也可以不处理,继续执行完
- 如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个InterruptedException异常。这个时候,我们可以通过捕获InterruptedException异常来终止线程的执行,具体可以通过return等退出或改变共享变量的值使其退出
- 如果线程是阻塞在io上,对应的资源会被关闭
interrupt相关的API
- interrupt() : 中断线程方法
- isInterrupted() : 返回线程是否被中断,中断状态保持不变
- interrupted() :返回线程是否被中断,但中断状态被清除。换句话说,如果线程被中断后,连续两次调用该方法,则第二次调用将返回 false。
源码
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this); // 中断阻塞的IO/NIO,关闭对应的资源
return;
}
}
interrupt0();
}
如源码注释所示:interrupt方法主要是设置中断状态,及对应阻塞资源的释放
public boolean isInterrupted() {
return isInterrupted(false);
}
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
private native boolean isInterrupted(boolean ClearInterrupted);
isInterrupted方法和interrupted可以放在一起比较,两个方法都是调用native的isInterrupted方法,两个都是测试线程是否被中断,并将中断状态返回。
不同之处在于:isInterrupted 不会清除中断状态, interrupted会清除中断状态
测试interrupt方法
public class InterruptTest {
public static int i = 0;
static int length = 100_000_000_0;
public static void main(String[] args) throws InterruptedException {
testNotInterruptIfSubThreadNotCatchInterruptState();
testWillThrowExceptionWhenSleep();
}
private static void testNotInterruptIfSubThreadNotCatchInterruptState() throws InterruptedException {
Thread t = new Thread(new NormalInterrupt());
t.start();
TimeUnit.SECONDS.sleep(1L);
t.interrupt();
System.out.println(Thread.currentThread().getName() + ": " + i);
}
static class NormalInterrupt implements Runnable {
@Override
public void run() {
//在其他线程中发出中断信号,是否中断还要看线程内部方法怎么写的,没有判断isInterrupted()并不会中断哦
//可以去掉for循环中的 !Thread.currentThread().isInterrupted()条件
for(int j = 0; j< length && !Thread.currentThread().isInterrupted(); j++) {
i = j;
}
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
private static void testWillThrowExceptionWhenSleep() throws InterruptedException {
Thread t = new Thread(new SleepInterrupt());
t.start();
TimeUnit.NANOSECONDS.sleep(1L);
t.interrupt();
System.out.println(Thread.currentThread().getName() + ": end");
}
static class SleepInterrupt implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": start");
try {
TimeUnit.SECONDS.sleep(2L);
} catch (InterruptedException e) {
e.printStackTrace();
}
//异常处理后,中断状态将被清除,所以结果是false
System.out.println(Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread().getName() + ": end");
}
}
}
运行结果:
main: 922319282
Thread-0: 922319282
Thread-1: start
main: end
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at InterruptTest$SleepInterrupt.run(InterruptTest.java:53)
at java.lang.Thread.run(Thread.java:748)
false
Thread-1: end