多线程(一) -- java线程(四) -- interrupt方法详解
1. interrupt打断线程
1.1 打断sleep,wait,join(阻塞状态)的线程
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(() -> {
log.debug("sleep;;;");
try {
Thread.sleep(5000); // sleep,join,wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1");
t1.start();
Thread.sleep(1000);
log.debug("interrupt");
t1.interrupt();
log.debug("打断标记:{}", t1.isInterrupted());
}
结果:
22:01:29.967 [t1] DEBUG com.multiThread.TestInterrupt1 - sleep;;;
22:01:30.963 [main] DEBUG com.multiThread.TestInterrupt1 - interrupt
22:01:30.963 [main] DEBUG com.multiThread.TestInterrupt1 - 打断标记:false
java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at com.yhx.toali.multiThread.TestInterrupt1.lambda$main$0(TestInterrupt1.java:16)
at java.base/java.lang.Thread.run(Thread.java:830)
可以看出阻塞状态的线程,被打断后会抛出一个异常;同时阻塞状态的线程被打断后,会将打断标记置为假。
1.2 打断正常执行的线程
给定一个死循环,如何打断这个死循环:
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(() -> {
while (true) {
}
}, "t1");
t1.start();
Thread.sleep(1000);
log.debug("interrupt");
t1.interrupt();
}
执行结果:可以看到程序并没有停止,还在一直执行
我们可以通过获取打断状态来停止这个线程:
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
log.debug("被打断,退出");
break;
}
}
}, "t1");
t1.start();
Thread.sleep(1000);
log.debug("interrupt");
t1.interrupt();
}
执行结果:
2. 两阶段终止模式
在一个线程t1中如何“优雅”地终止线程t2?这里的“优雅”指的是给t2一个料理后事的机会。
2.1 错误思路:
- 使用线程对象的stop()方法停止线程
- stop方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其他线程将永远无法获取锁
- 使用System.exit(int)方法停止线程
- 目的仅是停止一个线程,但是这种做法会让整个程序都停止
2.2 实现思路:
2.3 代码展示:
public class TestInterrupt3 {
public static void main(String[] args) throws InterruptedException{
TwoPhaseTermination twoPhaseTermination = new TwoPhaseTermination();
twoPhaseTermination.start();
Thread.sleep(3500);
twoPhaseTermination.stop();
}
}
@Slf4j
class TwoPhaseTermination {
private Thread monitor;
// 启动监控线程
public void start() {
monitor = new Thread(() -> {
while (true) {
Thread current = Thread.currentThread();
if (current.isInterrupted()) { // 获取终止状态
log.debug("料理后事");
break;
}
try {
Thread.sleep(1000); //情况1
log.debug("执行监控记录"); // 情况2
} catch (InterruptedException e) {
e.printStackTrace();
// 重新设置打断标记
current.interrupt();
}
}
});
monitor.start();
}
public void stop() {
monitor.interrupt();
}
}
执行结果:
22:44:24.932 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
22:44:25.947 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
22:44:26.948 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at com.yhx.toali.multiThread.TwoPhaseTermination.lambda$start$0(TestInterrupt3.java:36)
at java.base/java.lang.Thread.run(Thread.java:830)
22:44:27.432 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 料理后事
如果注释掉catch中的interrupt,查看执行结果:可以看到执行没有停止,这是因为:当线程在执行阻塞操作时(比如调用sleep/wait/yield/join方法时)调用了interrupt()会抛出InterruptException异常并且将该线程的”中断”标志位清空,会将线程的中断标志重新设置为false。所以在需要在线程是打断状态下重新调用interrupt方法,将线程状态设置为打断,触发料理后事方法。
3. interrupted()和isInterrupted()区别:
3.1 修改上述料理后事的代码:
if (current.isInterrupted()) {
log.debug("料理后事");
System.out.println(current.isInterrupted());
break;
}
结果:
11:52:43.814 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
11:52:44.823 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
11:52:45.831 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at com.yhx.toali.multiThread.TwoPhaseTermination.lambda$start$0(TestInterrupt3.java:42)
at java.base/java.lang.Thread.run(Thread.java:830)
11:52:46.316 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 料理后事
true
3.2 修改上述current.isInterrupted()
为monitor.interrupted()
:
if (monitor.interrupted()) {
log.debug("料理后事");
System.out.println(current.isInterrupted());
break;
}
结果:
11:54:41.316 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
11:54:42.349 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
11:54:43.356 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 执行监控记录
java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at com.yhx.toali.multiThread.TwoPhaseTermination.lambda$start$0(TestInterrupt3.java:42)
at java.base/java.lang.Thread.run(Thread.java:830)
11:54:43.793 [Thread-0] DEBUG com.yhx.toali.multiThread.TwoPhaseTermination - 料理后事
false
3.3 结论:
- 他们都是获取打断线程状态,但是isInterrupted不会清除打断标记,而interrupted会。
也就是说调用interrupted
方法会返回当前线程中断状态,同时清除中断状态(置为false) - Thread.interrupted() 线程静态方法,
Thread.currentThread().isInterrupted() 线程实例方法
3.4 源码查看:
interrupted:
public static boolean interrupted() {
Thread t = currentThread();
boolean interrupted = t.interrupted;
// We may have been interrupted the moment after we read the field,
// so only clear the field if we saw that it was set and will return
// true; otherwise we could lose an interrupt.
if (interrupted) {
t.interrupted = false;
clearInterruptEvent();
}
return interrupted;
}
isInterrupted:
public boolean isInterrupted() {
return interrupted;
}
可以看到他们拿到的都是Thread的成员变量interrupted的值,不过interrupted
拿到之后还会设置其为fasle
private volatile boolean interrupted;
m0_74009047: 2-3-4的普通删除那有一点我看不懂,如果所谓当前节点的兄弟节点不是二叉节点但有子结点,你把他的数据借给了当前节点,那他自己多的那一个孩子该怎么办呢
syhleo: 引用「g在Bean的生命周期中,会调用BeanPostProcessor这个后置处理器,内部就是用策略模式」 这个实现并不是策略模式,spring底层在bean的生命周期中,是会for循环调用这些扩展点的。如果你理解为策略模式,相当于每一次都会把所有的策略执行一次。
做而论道_CS: 计算机中,使用二进制,是没错的。 但是,数值、代码,是有区别的。 虽然,它们都是二进制。 但是,数值和代码,并不是相等的关系。 比如,你的学号,你的电话号码,能相等吗? 许多计算机专家,都是稀里糊涂的乱讲!
做而论道_CS: 另外,你写的: [-1] = [10000001]原 = [11111110]反 = [11111111]补 这写法,也是错误的。 它们之间,不是相等的,不能用等号(=)连在一起。 应该分开写: [-1]原 = 1000 0001; [-1]反 = 1111 1110; [-1]补 = 1111 1111。 当然,这肯定不是你的错。 很多计算机教材的作者,基本概念都不清。 写的书,都是错误百出的。
做而论道_CS: 从 “原码反码取反加一” 开始学习计算机知识,就完蛋了。 都学完了,你也理解不了: 负数,为什么要用正数(补码)代替? 正数,为什么就不用变换呢? 减法,怎么就能用加法实现? 你虽然可以背下来一些公式,能做一些加减运算, 但是,【知其然不知其所以然】! 大学,其实,就是专家卖弄垃圾的场所。 有用的东西,基本上,都没有讲。