Java并发编程 interrupt()方法示例详解
作者:k3ruanren
interrupt()用法
打断正常运行的线程
interrrupt()方法可以用来打断正在运行的线程,也可以打断sleep()、wait()、join()情况下的线程,但是这些情况下被打断线程的打断标记不同。
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.TimeUnit; @Slf4j public class InterruptTest { public static void main(String[] args) throws InterruptedException { //创建一个线程 Thread t1 = new Thread(() -> { //让线程一直死循环运行 log.debug("t1开始运行....."); while(true){ } },"t1"); //启动线程t1 t1.start(); //main主线程一秒后进行打断操作 TimeUnit.MILLISECONDS.sleep(1000); log.debug("interrupt....."); t1.interrupt(); } }
通过控制台,可以很清晰的看到,main主线程在执行完打断操作后,t1线程并未终止运行,而是继续执行:
但是如果我们查看线程t1的打断标记会发现,t1线程的打断标记确实为true:
Boolean interrupted = Thread.currentThread().isInterrupted();
这是因为main主线程执行interrupt打断操作,只是通知t1线程,我现在要打断你,但是具体的执行操作还得看t1线程,即t1线程收到main主线程的打断通知后,由t1线程自己觉得是继续运行还是被打断,从而让出cpu,这样的好处在于线程t1如果在执行某些很重要的任务,突然被其他线程强制打断可能会造成很严重的后果,这时可以让t1线程自己选择是否停止工作,也可以在停止工作之前做一些料理后事的工作 。
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.TimeUnit; @Slf4j public class InterruptTest { public static void main(String[] args) throws InterruptedException { //创建一个线程 Thread t1 = new Thread(() -> { //让线程一直死循环运行 log.debug("t1开始运行....."); while(true){ Boolean interrupted = Thread.currentThread().isInterrupted(); //选择被打断后的执行操作 if(interrupted){ log.debug("被打断,停止运行..."); break; } } },"t1"); //启动线程t1 t1.start(); //main主线程一秒后进行打断操作 TimeUnit.MILLISECONDS.sleep(1000); log.debug("interrupt....."); t1.interrupt(); } }
14:41:02.906 [t1] DEBUG InterruptTest - t1开始运行.....
14:41:03.908 [main] DEBUG InterruptTest - interrupt.....
14:41:03.908 [t1] DEBUG InterruptTest - 被打断,停止运行...
打断sleep状态的线程
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.TimeUnit; @Slf4j public class InterruptTest { public static void main(String[] args) throws InterruptedException { //创建一个线程 Thread t1 = new Thread(() -> { //让线程一直死循环运行 log.debug("t1开始运行....."); //t1线程休眠3秒 try { log.debug("t1 is sleeping..."); TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } },"t1"); //启动线程t1 t1.start(); //main主线程一秒后进行打断操作 TimeUnit.MILLISECONDS.sleep(1000); log.debug("interrupt....."); t1.interrupt(); //查看t1线程的打断标记 Boolean interrupted = t1.isInterrupted(); log.debug(interrupted.toString()); }
打断sleep状态的线程,会抛出InterruptedException异常,并且打断标记是false而不是true:
14:50:25.532 [t1] DEBUG InterruptTest - t1开始运行..... 14:50:25.536 [t1] DEBUG InterruptTest - t1 is sleeping... 14:50:26.533 [main] DEBUG InterruptTest - interrupt..... 14:50:26.544 [main] DEBUG InterruptTest - false Exception in thread "t1" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted at InterruptTest.lambda$main$0(InterruptTest.java:17) at java.base/java.lang.Thread.run(Thread.java:829) Caused by: java.lang.InterruptedException: sleep interrupted at java.base/java.lang.Thread.sleep(Native Method) at java.base/java.lang.Thread.sleep(Thread.java:334) at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446) at InterruptTest.lambda$main$0(InterruptTest.java:15) ... 1 more Process finished with exit code 0
两阶段终止模式 Two Phase Termination
在线程t1中如何优雅的终止线程t2?
- 使用stop()方法终止线程,这显然是不好的行为,因为一个线程调用了stop()方法,那么这个线程就被彻底杀死了,如果该线程正在访问一些共享资源并且加了锁,那么stop()之后该线程将再也不能释放锁,其他线程也就无法访问那些共享资源了。
- 使用System.exit()方法,这也是错误的选择,这会终止整个程序!
正确的做法是采用两阶段终止模式,具体流程如下图所示:
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.TimeUnit; @Slf4j public class TwoPhaseTest { public static void main(String[] args) throws InterruptedException { TwoPhaseTermination tpt = new TwoPhaseTermination(); tpt.start(); TimeUnit.SECONDS.sleep(4); tpt.stop(); } } /** * 监控类 */ @Slf4j class TwoPhaseTermination{ //监控线程 private Thread monitor; //线程启动方法 public void start(){ monitor = new Thread(()->{ while(true){ Thread thread = Thread.currentThread(); Boolean interrupted = thread.isInterrupted(); if(interrupted){ log.debug("料理后事....."); break; } try { TimeUnit.SECONDS.sleep(1); //每隔一秒钟执行监控任务 log.debug("监控中...."); } catch (InterruptedException e) { e.printStackTrace(); //如果在sleep状态被打断,那么中断标记为false,需要手动置为true thread.interrupt(); } }}); //启动线程 monitor.start(); } //线程终止方法 public void stop(){ //打断线程 monitor.interrupt(); } }
15:38:11.046 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
15:38:12.054 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
15:38:13.060 [Thread-0] DEBUG TwoPhaseTermination - 监控中....
java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at java.base/java.lang.Thread.sleep(Thread.java:334)
at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446)
at TwoPhaseTermination.lambda$start$0(TwoPhaseTest.java:33)
at java.base/java.lang.Thread.run(Thread.java:829)
15:38:14.014 [Thread-0] DEBUG TwoPhaseTermination - 料理后事.....Process finished with exit code 0
打断park()线程
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; @Slf4j public class ParkTest { public static void main(String[] args) throws InterruptedException { test(); } private static void test() throws InterruptedException { Thread t1 = new Thread(()->{ log.debug("park......"); LockSupport.park();//线程在此卡住,不继续向下执行 log.debug("unpark......."); log.debug("打断状态:{}",Thread.currentThread().isInterrupted()); },"t1"); t1.start(); //主线程main休眠2秒 TimeUnit.SECONDS.sleep(2); //打断t1线程 t1.interrupt(); } }
15:51:24.581 [t1] DEBUG ParkTest - park......
15:51:26.582 [t1] DEBUG ParkTest - unpark.......
15:51:26.584 [t1] DEBUG ParkTest - 打断状态:true
到此这篇关于Java并发编程 interrupt()方法的文章就介绍到这了,更多相关Java并发编程 interrupt()方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!