interrupt 方法打断线程
- case1:打断sleep, wait, join (阻塞)的线程
- case2:打断运行中的线程
打断阻塞状态中的线程,会抛出一个InterruptedException
异常,并且会重置打断标记
。
- 介绍一下打断标记
Thread类里有一个isInterrupted
方法可以返回当前线程是否被打断,被打断返回true
,否则false
。
public boolean isInterrupted() {
return isInterrupted(false); // 这里的false指不会重置打断标记}
还有一个类似的静态方法interrupted
也可以返回当前线程是否被打断,被打断返回true
,否则false
,但是会重置打断标记为false。
public static boolean interrupted() {
return currentThread().isInterrupted(true); // 这里的true指会重置打断标记}
打断阻塞状态的线程
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("sleep...");try {
Thread.sleep(5000); // wait, join} catch (InterruptedException e) {
e.printStackTrace();}},"t1");t1.start();Thread.sleep(1000);log.debug("interrupt");log.debug("打断标记:{}", t1.isInterrupted()); // 1t1.interrupt();log.debug("打断标记:{}", t1.isInterrupted()); // 2}
}/*Output: 22:29:08.624 c.Test11 [t1] - sleep... 22:29:09.621 c.Test11 [main] - interrupt 22:29:09.621 c.Test11 [main] - 打断标记:false 22:29:09.624 c.Test11 [main] - 打断标记:false java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at cn.itcast.test.Test11.lambda$main$0(Test11.java:12)at java.lang.Thread.run(Thread.java:748) */
上面两个false是意义不同的,第一个代表当前线程正常运行,没有被打断;而第二个false代表线程在sleep, wait, join 中(阻塞状态)被打断,会抛出异常并将打断标记重置为false。
打断正常运行的线程
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while(true) {
System.out.println("isInterrupted状态: " + (Thread.currentThread().isInterrupted()));}}, "t1");t1.start();Thread.sleep(1000);log.debug("interrupt");t1.interrupt();}
}/*Output: ... isInterrupted状态: false isInterrupted状态: false isInterrupted状态: false 22:43:30.383 c.Test12 [main] - interrupt isInterrupted状态: true isInterrupted状态: true isInterrupted状态: true ...
打断后标记变为true, 但是进程并没有停止,那么这个打断到底有啥用啊?我们怎么让被打断后的进程停下来哪?我们可以借助打断标记,如果打断标记为真,就手动退出进程。
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while(true) {
boolean interrupted = Thread.currentThread().isInterrupted();if(interrupted) {
log.debug("被打断了, 退出循环");break;}}}, "t1");t1.start();Thread.sleep(1000);log.debug("interrupt");t1.interrupt();}
}/*Output: 22:52:17.742 c.Test12 [main] - interrupt 22:52:17.747 c.Test12 [t1] - 被打断了, 退出循环 */
interrupt应用:多线程设计模式之两阶段终止
Two Phase Termination
:在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。
错误思路
- 使用线程对象的 stop() 方法停止线程
- stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁, 其它线程将永远无法获取锁
- 使用 System.exit(int) 方法停止线程
- 目的仅是停止一个线程,但这种做法会让整个程序都停止
两阶段终止模式
- 应用场景:后台监控线程(需要设置停止选项)
- 思路
@Slf4j(topic = "c.TwoPhaseTermination")
public class Test_1 {
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination_1 tpt = new TwoPhaseTermination_1();tpt.start();Thread.sleep(3500);log.debug("停止监控");tpt.stop();}
}@Slf4j(topic = "c.TwoPhaseTermination")
class TwoPhaseTermination_1 {
// 监控线程private Thread monitorThread;// 启动监控线程public void start() {
monitorThread = new Thread(() -> {
while (true) {
Thread current = Thread.currentThread();// 是否被打断if (current.isInterrupted()) {
log.debug("料理后事");break;}try {
Thread.sleep(1000); // 睡眠时被打断log.debug("执行监控记录"); // 正常打断} catch (InterruptedException e) {
e.printStackTrace();// 当抛出异常时,重新设置打断标记current.interrupt();}}}, "monitor");monitorThread.start();}// 停止监控线程public void stop() {
monitorThread.interrupt();}
}/*Output: 00:30:54.263 c.TwoPhaseTermination [monitor] - 执行监控记录 00:30:55.263 c.TwoPhaseTermination [monitor] - 执行监控记录 00:30:56.265 c.TwoPhaseTermination [monitor] - 执行监控记录 00:30:56.765 c.TwoPhaseTermination [main] - 停止监控 00:30:56.765 c.TwoPhaseTermination [monitor] - 料理后事 java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at cn.itcast.test.TwoPhaseTermination_1.lambda$start$0(Test_1.java:33)at java.lang.Thread.run(Thread.java:748) */
在睡眠时被打断,抛出异常并优雅的退出线程。正常运行时被打断,优雅的退出线程。