本文基于jdk1.8
一.那个Thread中断一下
如何停止一个运行线程呢?
很久以前通过stop(),这是属于抢占式的中断。强制停止一个线程,可能造成不可预估的后果。
举个例子:
例如正在玩游戏,耗时n久通过了,没存档,然后突然断电了。。。,这个后果是砸显示器还是砸显示器呢。
现在推荐调用interrupt(),这属于协作式中断。线程中断不代表线程的立即死亡,可能是中断返回等待新的任务,或是线程忙完任务选择合适的时机再死亡。
这意味着,调用interrupt,只是标识了线程中断状态,至于要不要死亡或者什么时候死亡这是线程自身决定的。
二.线程状态
在进入线程中断之前,先了解线程都有哪些状态:
- NEW
这个状态,表示线程还没启动,只是创建了一个线程 - RUNNABLE
jVM中处于可运行状态。 - BLOCKED
线程等待监视器锁的状态,例如IO堵塞住线程 - WAITING
等待线程的状态,等待另外线程执行特定操作。可以调用如下方法进入该状态:
- Object.wait没有超时
- Thread.join没有超时
- LockSupport.park
- TIMED_WAITING
线程超时等待状态,同 WAITING状态相似,只是多了限时操作。如下方法进入该状态:
Thread.sleep
Object.wait超时
Thread.join超时
LockSupport.parkNanos
LockSupport.parkUntil - TERMINATED
线程已完成执行的状态
这里有个注意点,不要搞混了BLOCKED和WAITING,翻译过来,感觉含义类似。
- WAITING和TIMED_WAITING状态就是我们日常理解的“堵塞”,线程真的堵住了。
- BLOCKED状态是指线程不占用cpu资源,但线程还在运行了,可能占用了网卡等其他资源
三. 来,断一下
不多说,直接测试下,哪些状态下,中断生效
1. NEW
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("中断了");
});
System.out.println("线程状态:"+thread.getState());
System.out.println("线程中断状态前:"+thread.isInterrupted());
thread.interrupt();
System.out.println("线程中断状态后:"+thread.isInterrupted());
}
运行结果如下,对于NEW状态,中断操作没有影响
2. RUNNABLE
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
Thread t1 = Thread.currentThread();
System.out.println("线程状态:"+t1.getState());
System.out.println("线程中断状态前:"+t1.isInterrupted());
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程中断状态后:"+true);
break;
}
}
System.out.println("断了断了");
});
thread.start();
Thread.sleep(10L);
System.out.println("开始中断");
thread.interrupt();
}
运行结果如下,对于RUNNABLE状态,中断操作会修改中断状态为true,但不影响线程继续运行。
3. BLOCKED
public class Solution {
public static synchronized void addNum(boolean sleep) {
if (!sleep) {
return;
}
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
Solution.addNum(true);
});
Thread thread2 = new Thread(() -> {
Solution.addNum(false);
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程中断状态后:" + true);
break;
}
}
System.out.println("断了断了");
});
thread.start();
Thread.sleep(10L);
thread2.start();
System.out.println("线程中断状态前:" + thread2.isInterrupted());
System.out.println("线程状态:" + thread2.getState());
System.out.println("开始中断");
thread2.interrupt();
}
}
运行结果如下,对于BLOCKED状态,中断操作会修改中断状态为true,但不影响线程继续运行。
4. WAITING
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("线程中断状态前:" + Thread.currentThread().isInterrupted());
LockSupport.park();
System.out.println("断了断了");
});
thread.start();
Thread.sleep(50L);
System.out.println("线程状态:" + thread.getState());
thread.interrupt();
System.out.println("线程中断状态后:" + thread.isInterrupted());
}
运行结果如下,对于WAITING状态,中断操作会修改中断状态为true,且影响线程运行。
这里调用LockSupport.park不抛出中断异常,其他例如wait()方法会抛异常的
5. TIMED_WAITING
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("线程中断状态前:" + Thread.currentThread().isInterrupted());
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("断了断了");
});
thread.start();
Thread.sleep(50L);
System.out.println("线程状态:" + thread.getState());
thread.interrupt();
System.out.println("线程中断状态后:" + thread.isInterrupted());
}
运行结果如下,对于TIMED_WAITING状态,中断操作会修改中断状态为true,且影响线程运行。
6. TERMINATED
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("中断了");
});
thread.start();
Thread.sleep(2000L);
System.out.println("线程状态:"+thread.getState());
System.out.println("线程中断状态前:"+thread.isInterrupted());
thread.interrupt();
System.out.println("线程中断状态后:"+thread.isInterrupted());
}
运行结果如下,对于TERMINATED状态,中断操作没有影响
7.堵塞已中断过的线程
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("启动线程");
LockSupport.park();
System.out.println("恢复了继续走");
System.out.println("看看状态怎么样:"+Thread.currentThread().isInterrupted());
LockSupport.park();
System.out.println("同样的招式对圣斗士无效的");
// 重置状态,并返回之前的状态
System.out.println("重置下,看下之前的状态:"+Thread.interrupted());
System.out.println("看看当前状态2:"+Thread.currentThread().isInterrupted());
LockSupport.park();
System.out.println("断了断了");
});
thread.start();
Thread.sleep(50L);
System.out.println("开始中断线程" );
thread.interrupt();
}
运行结果如下,对已中断的线程,再次堵塞失效了,直到恢复默认中断状态才能生效。
四.总结
根据上面的测试结果,中断操作,总结如下:
- NEW ,TERMINATED对于这两种状态,中断操作没有一丝影响。
- RUNNABLE,BLOCKED 中断只会修改当前中断状态,但不影响线程运行。
- WAITING,TIMED_WAITING 中断会打断当前的堵塞状态,且修改当前中断状态。除了LockSupport.park外的操作会抛出中断异常。
- 对已中断的线程,堵塞操作无效,除非恢复默认中断状态。