行业资讯

多线程(一) - java线程(四) - interrupt方法详解

发布时间:2026/8/21 14:26:59
多线程(一) - java线程(四) - interrupt方法详解 1. interrupt打断线程1.1 打断sleepwaitjoin阻塞状态的线程publicstaticvoidmain(String[]args)throwsInterruptedException{Threadt1newThread(()-{log.debug(sleep;;;);try{Thread.sleep(5000);// sleep,join,wait}catch(InterruptedExceptione){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 - interrupt22:01:30.963[main]DEBUG com.multiThread.TestInterrupt1 - 打断标记false java.lang.InterruptedException:sleepinterrupted 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 打断正常执行的线程给定一个死循环如何打断这个死循环publicstaticvoidmain(String[]args)throwsInterruptedException{Threadt1newThread(()-{while(true){}},t1);t1.start();Thread.sleep(1000);log.debug(interrupt);t1.interrupt();}执行结果可以看到程序并没有停止还在一直执行我们可以通过获取打断状态来停止这个线程publicstaticvoidmain(String[]args)throwsInterruptedException{Threadt1newThread(()-{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 代码展示publicclassTestInterrupt3{publicstaticvoidmain(String[]args)throwsInterruptedException{TwoPhaseTerminationtwoPhaseTerminationnewTwoPhaseTermination();twoPhaseTermination.start();Thread.sleep(3500);twoPhaseTermination.stop();}}Slf4jclassTwoPhaseTermination{privateThreadmonitor;// 启动监控线程publicvoidstart(){monitornewThread(()-{while(true){ThreadcurrentThread.currentThread();if(current.isInterrupted()){// 获取终止状态log.debug(料理后事);break;}try{Thread.sleep(1000);//情况1log.debug(执行监控记录);// 情况2}catch(InterruptedExceptione){e.printStackTrace();// 重新设置打断标记current.interrupt();}}});monitor.start();}publicvoidstop(){monitor.interrupt();}}执行结果22:44:24.932[Thread-0]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录22:44:25.947[Thread-0]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录22:44:26.948[Thread-0]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录java.lang.InterruptedException:sleep interrupted at java.base/java.lang.Thread.sleep(NativeMethod)atcom.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]DEBUGcom.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]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录11:52:44.823[Thread-0]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录11:52:45.831[Thread-0]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录java.lang.InterruptedException:sleep interrupted at java.base/java.lang.Thread.sleep(NativeMethod)atcom.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]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-料理后事true3.2 修改上述current.isInterrupted()为monitor.interrupted()if(monitor.interrupted()){log.debug(料理后事);System.out.println(current.isInterrupted());break;}结果11:54:41.316[Thread-0]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录11:54:42.349[Thread-0]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录11:54:43.356[Thread-0]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-执行监控记录java.lang.InterruptedException:sleep interrupted at java.base/java.lang.Thread.sleep(NativeMethod)atcom.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]DEBUGcom.yhx.toali.multiThread.TwoPhaseTermination-料理后事false3.3 结论他们都是获取打断线程状态但是isInterrupted不会清除打断标记而interrupted会。也就是说调用interrupted方法会返回当前线程中断状态同时清除中断状态置为falseThread.interrupted() 线程静态方法Thread.currentThread().isInterrupted() 线程实例方法3.4 源码查看interruptedpublicstaticbooleaninterrupted(){ThreadtcurrentThread();booleaninterruptedt.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.interruptedfalse;clearInterruptEvent();}returninterrupted;}isInterruptedpublicbooleanisInterrupted(){returninterrupted;}可以看到他们拿到的都是Thread的成员变量interrupted的值不过interrupted拿到之后还会设置其为fasleprivatevolatilebooleaninterrupted;