Java并發(fā)編程 interrupt()方法示例詳解
interrupt()用法
打斷正常運行的線程
interrrupt()方法可以用來打斷正在運行的線程,也可以打斷sleep()、wait()、join()情況下的線程,但是這些情況下被打斷線程的打斷標(biāo)記不同。
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.TimeUnit; @Slf4j public class InterruptTest { public static void main(String[] args) throws InterruptedException { //創(chuàng)建一個線程 Thread t1 = new Thread(() -> { //讓線程一直死循環(huán)運行 log.debug("t1開始運行....."); while(true){ } },"t1"); //啟動線程t1 t1.start(); //main主線程一秒后進(jìn)行打斷操作 TimeUnit.MILLISECONDS.sleep(1000); log.debug("interrupt....."); t1.interrupt(); } }
通過控制臺,可以很清晰的看到,main主線程在執(zhí)行完打斷操作后,t1線程并未終止運行,而是繼續(xù)執(zhí)行:
但是如果我們查看線程t1的打斷標(biāo)記會發(fā)現(xiàn),t1線程的打斷標(biāo)記確實為true:
Boolean interrupted = Thread.currentThread().isInterrupted();
這是因為main主線程執(zhí)行interrupt打斷操作,只是通知t1線程,我現(xiàn)在要打斷你,但是具體的執(zhí)行操作還得看t1線程,即t1線程收到main主線程的打斷通知后,由t1線程自己覺得是繼續(xù)運行還是被打斷,從而讓出cpu,這樣的好處在于線程t1如果在執(zhí)行某些很重要的任務(wù),突然被其他線程強(qiáng)制打斷可能會造成很嚴(yán)重的后果,這時可以讓t1線程自己選擇是否停止工作,也可以在停止工作之前做一些料理后事的工作 。
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.TimeUnit; @Slf4j public class InterruptTest { public static void main(String[] args) throws InterruptedException { //創(chuàng)建一個線程 Thread t1 = new Thread(() -> { //讓線程一直死循環(huán)運行 log.debug("t1開始運行....."); while(true){ Boolean interrupted = Thread.currentThread().isInterrupted(); //選擇被打斷后的執(zhí)行操作 if(interrupted){ log.debug("被打斷,停止運行..."); break; } } },"t1"); //啟動線程t1 t1.start(); //main主線程一秒后進(jìn)行打斷操作 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狀態(tài)的線程
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.TimeUnit; @Slf4j public class InterruptTest { public static void main(String[] args) throws InterruptedException { //創(chuàng)建一個線程 Thread t1 = new Thread(() -> { //讓線程一直死循環(huán)運行 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主線程一秒后進(jìn)行打斷操作 TimeUnit.MILLISECONDS.sleep(1000); log.debug("interrupt....."); t1.interrupt(); //查看t1線程的打斷標(biāo)記 Boolean interrupted = t1.isInterrupted(); log.debug(interrupted.toString()); }
打斷sleep狀態(tài)的線程,會拋出InterruptedException異常,并且打斷標(biāo)記是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中如何優(yōu)雅的終止線程t2?
- 使用stop()方法終止線程,這顯然是不好的行為,因為一個線程調(diào)用了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(); } } /** * 監(jiān)控類 */ @Slf4j class TwoPhaseTermination{ //監(jiān)控線程 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); //每隔一秒鐘執(zhí)行監(jiān)控任務(wù) log.debug("監(jiān)控中...."); } catch (InterruptedException e) { e.printStackTrace(); //如果在sleep狀態(tài)被打斷,那么中斷標(biāo)記為false,需要手動置為true thread.interrupt(); } }}); //啟動線程 monitor.start(); } //線程終止方法 public void stop(){ //打斷線程 monitor.interrupt(); } }
15:38:11.046 [Thread-0] DEBUG TwoPhaseTermination - 監(jiān)控中....
15:38:12.054 [Thread-0] DEBUG TwoPhaseTermination - 監(jiān)控中....
15:38:13.060 [Thread-0] DEBUG TwoPhaseTermination - 監(jiān)控中....
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();//線程在此卡住,不繼續(xù)向下執(zhí)行 log.debug("unpark......."); log.debug("打斷狀態(tài):{}",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 - 打斷狀態(tài):true
到此這篇關(guān)于Java并發(fā)編程 interrupt()方法的文章就介紹到這了,更多相關(guān)Java并發(fā)編程 interrupt()方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GateWay路由規(guī)則與動態(tài)路由詳細(xì)介紹
這篇文章主要介紹了GateWay路由規(guī)則與GateWay動態(tài)路由,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09springboot集成flyway自動創(chuàng)表的詳細(xì)配置
Flayway是一款數(shù)據(jù)庫版本控制管理工具,支持?jǐn)?shù)據(jù)庫版本自動升級,Migrations可以寫成sql腳本,也可以寫在java代碼里;本文通過實例代碼給大家介紹springboot集成flyway自動創(chuàng)表的詳細(xì)過程,感興趣的朋友一起看看吧2021-06-06SpringBoot整合MinIO實現(xiàn)文件存儲系統(tǒng)的代碼示例
在現(xiàn)代的應(yīng)用程序中,文件存儲和管理是一個常見的需求,MinIO是一個開源的對象存儲系統(tǒng),與Spring?Boot框架結(jié)合使用,可以快速構(gòu)建高性能的文件存儲系統(tǒng),本文將介紹如何使用Spring?Boot和MinIO來實現(xiàn)文件存儲系統(tǒng)2023-06-06Spring Boot 實現(xiàn)Restful webservice服務(wù)端示例代碼
這篇文章主要介紹了Spring Boot 實現(xiàn)Restful webservice服務(wù)端示例代碼,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-11-11spring-boot-maven-plugin:unknown的完美解決方法
這篇文章主要介紹了spring-boot-maven-plugin:unknown的完美解決方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11使用System.exit()來優(yōu)雅地終止SpringBoot項目的代碼示例
System.exit() 方法是 Java 中用于退出程序的方法,它接受一個整數(shù)參數(shù),通常被用來指示程序的退出狀態(tài),本文給大家介紹了如何使用System.exit()來優(yōu)雅地終止SpringBoot項目,需要的朋友可以參考下2024-08-08postman測試傳入List<String>參數(shù)方式
這篇文章主要介紹了postman測試傳入List<String>參數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08spring的xml文件打開沒有namespace等操作選項的解決方案
這篇文章主要介紹了spring的xml文件打開沒有namespace等操作選項的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09