Java并發(fā)編程 interrupt()方法示例詳解
interrupt()用法
打斷正常運(yùn)行的線程
interrrupt()方法可以用來打斷正在運(yùn)行的線程,也可以打斷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)建一個(gè)線程 Thread t1 = new Thread(() -> { //讓線程一直死循環(huán)運(yùn)行 log.debug("t1開始運(yùn)行....."); while(true){ } },"t1"); //啟動(dòng)線程t1 t1.start(); //main主線程一秒后進(jìn)行打斷操作 TimeUnit.MILLISECONDS.sleep(1000); log.debug("interrupt....."); t1.interrupt(); } }
通過控制臺(tái),可以很清晰的看到,main主線程在執(zhí)行完打斷操作后,t1線程并未終止運(yùn)行,而是繼續(xù)執(zhí)行:
但是如果我們查看線程t1的打斷標(biāo)記會(huì)發(fā)現(xiàn),t1線程的打斷標(biāo)記確實(shí)為true:
Boolean interrupted = Thread.currentThread().isInterrupted();
這是因?yàn)閙ain主線程執(zhí)行interrupt打斷操作,只是通知t1線程,我現(xiàn)在要打斷你,但是具體的執(zhí)行操作還得看t1線程,即t1線程收到main主線程的打斷通知后,由t1線程自己覺得是繼續(xù)運(yùn)行還是被打斷,從而讓出cpu,這樣的好處在于線程t1如果在執(zhí)行某些很重要的任務(wù),突然被其他線程強(qiáng)制打斷可能會(huì)造成很嚴(yán)重的后果,這時(shí)可以讓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)建一個(gè)線程 Thread t1 = new Thread(() -> { //讓線程一直死循環(huán)運(yùn)行 log.debug("t1開始運(yùn)行....."); while(true){ Boolean interrupted = Thread.currentThread().isInterrupted(); //選擇被打斷后的執(zhí)行操作 if(interrupted){ log.debug("被打斷,停止運(yùn)行..."); break; } } },"t1"); //啟動(dòng)線程t1 t1.start(); //main主線程一秒后進(jìn)行打斷操作 TimeUnit.MILLISECONDS.sleep(1000); log.debug("interrupt....."); t1.interrupt(); } }
14:41:02.906 [t1] DEBUG InterruptTest - t1開始運(yùn)行.....
14:41:03.908 [main] DEBUG InterruptTest - interrupt.....
14:41:03.908 [t1] DEBUG InterruptTest - 被打斷,停止運(yùn)行...
打斷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)建一個(gè)線程 Thread t1 = new Thread(() -> { //讓線程一直死循環(huán)運(yùn)行 log.debug("t1開始運(yùn)行....."); //t1線程休眠3秒 try { log.debug("t1 is sleeping..."); TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { throw new RuntimeException(e); } },"t1"); //啟動(dòng)線程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)的線程,會(huì)拋出InterruptedException異常,并且打斷標(biāo)記是false而不是true:
14:50:25.532 [t1] DEBUG InterruptTest - t1開始運(yùn)行..... 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()方法終止線程,這顯然是不好的行為,因?yàn)橐粋€(gè)線程調(diào)用了stop()方法,那么這個(gè)線程就被徹底殺死了,如果該線程正在訪問一些共享資源并且加了鎖,那么stop()之后該線程將再也不能釋放鎖,其他線程也就無法訪問那些共享資源了。
- 使用System.exit()方法,這也是錯(cuò)誤的選擇,這會(huì)終止整個(gè)程序!
正確的做法是采用兩階段終止模式,具體流程如下圖所示:
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; //線程啟動(dòng)方法 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,需要手動(dòng)置為true thread.interrupt(); } }}); //啟動(dòng)線程 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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GateWay路由規(guī)則與動(dòng)態(tài)路由詳細(xì)介紹
這篇文章主要介紹了GateWay路由規(guī)則與GateWay動(dòng)態(tài)路由,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09springboot集成flyway自動(dòng)創(chuàng)表的詳細(xì)配置
Flayway是一款數(shù)據(jù)庫版本控制管理工具,支持?jǐn)?shù)據(jù)庫版本自動(dòng)升級(jí),Migrations可以寫成sql腳本,也可以寫在java代碼里;本文通過實(shí)例代碼給大家介紹springboot集成flyway自動(dòng)創(chuàng)表的詳細(xì)過程,感興趣的朋友一起看看吧2021-06-06SpringBoot整合MinIO實(shí)現(xiàn)文件存儲(chǔ)系統(tǒng)的代碼示例
在現(xiàn)代的應(yīng)用程序中,文件存儲(chǔ)和管理是一個(gè)常見的需求,MinIO是一個(gè)開源的對(duì)象存儲(chǔ)系統(tǒng),與Spring?Boot框架結(jié)合使用,可以快速構(gòu)建高性能的文件存儲(chǔ)系統(tǒng),本文將介紹如何使用Spring?Boot和MinIO來實(shí)現(xiàn)文件存儲(chǔ)系統(tǒng)2023-06-06Spring Boot 實(shí)現(xiàn)Restful webservice服務(wù)端示例代碼
這篇文章主要介紹了Spring Boot 實(shí)現(xiàn)Restful webservice服務(wù)端示例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-11-11spring-boot-maven-plugin:unknown的完美解決方法
這篇文章主要介紹了spring-boot-maven-plugin:unknown的完美解決方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11使用System.exit()來優(yōu)雅地終止SpringBoot項(xiàng)目的代碼示例
System.exit() 方法是 Java 中用于退出程序的方法,它接受一個(gè)整數(shù)參數(shù),通常被用來指示程序的退出狀態(tài),本文給大家介紹了如何使用System.exit()來優(yōu)雅地終止SpringBoot項(xiàng)目,需要的朋友可以參考下2024-08-08postman測試傳入List<String>參數(shù)方式
這篇文章主要介紹了postman測試傳入List<String>參數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java類成員訪問權(quán)限控制知識(shí)總結(jié)
這篇文章主要介紹了Java類成員訪問權(quán)限控制知識(shí)總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04Mybatis實(shí)現(xiàn)動(dòng)態(tài)建表代碼實(shí)例
這篇文章主要介紹了Mybatis實(shí)現(xiàn)動(dòng)態(tài)建表代碼實(shí)例,解釋一下,就是指根據(jù)傳入的表名,動(dòng)態(tài)地創(chuàng)建數(shù)據(jù)庫表,以供后面的業(yè)務(wù)場景使用,2023-10-10
而使用 Mybatis 的動(dòng)態(tài) SQL,就能很好地為我們解決這個(gè)問題,需要的朋友可以參考下spring的xml文件打開沒有namespace等操作選項(xiàng)的解決方案
這篇文章主要介紹了spring的xml文件打開沒有namespace等操作選項(xiàng)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09