Java并發(fā)編程 interrupt()方法示例詳解
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 {
//創(chuàng)建一個線程
Thread t1 = new Thread(() -> {
//讓線程一直死循環(huán)運行
log.debug("t1開始運行.....");
while(true){
}
},"t1");
//啟動線程t1
t1.start();
//main主線程一秒后進行打斷操作
TimeUnit.MILLISECONDS.sleep(1000);
log.debug("interrupt.....");
t1.interrupt();
}
}通過控制臺,可以很清晰的看到,main主線程在執(zhí)行完打斷操作后,t1線程并未終止運行,而是繼續(xù)執(zhí)行:

但是如果我們查看線程t1的打斷標記會發(fā)現(xiàn),t1線程的打斷標記確實為true:
Boolean interrupted = Thread.currentThread().isInterrupted();

這是因為main主線程執(zhí)行interrupt打斷操作,只是通知t1線程,我現(xiàn)在要打斷你,但是具體的執(zhí)行操作還得看t1線程,即t1線程收到main主線程的打斷通知后,由t1線程自己覺得是繼續(xù)運行還是被打斷,從而讓出cpu,這樣的好處在于線程t1如果在執(zhí)行某些很重要的任務,突然被其他線程強制打斷可能會造成很嚴重的后果,這時可以讓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主線程一秒后進行打斷操作
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主線程一秒后進行打斷操作
TimeUnit.MILLISECONDS.sleep(1000);
log.debug("interrupt.....");
t1.interrupt();
//查看t1線程的打斷標記
Boolean interrupted = t1.isInterrupted();
log.debug(interrupted.toString());
}打斷sleep狀態(tài)的線程,會拋出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中如何優(yōu)雅的終止線程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();
}
}
/**
* 監(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)控任務
log.debug("監(jiān)控中....");
} catch (InterruptedException e) {
e.printStackTrace();
//如果在sleep狀態(tài)被打斷,那么中斷標記為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
到此這篇關于Java并發(fā)編程 interrupt()方法的文章就介紹到這了,更多相關Java并發(fā)編程 interrupt()方法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
GateWay路由規(guī)則與動態(tài)路由詳細介紹
這篇文章主要介紹了GateWay路由規(guī)則與GateWay動態(tài)路由,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
springboot集成flyway自動創(chuàng)表的詳細配置
Flayway是一款數(shù)據(jù)庫版本控制管理工具,支持數(shù)據(jù)庫版本自動升級,Migrations可以寫成sql腳本,也可以寫在java代碼里;本文通過實例代碼給大家介紹springboot集成flyway自動創(chuàng)表的詳細過程,感興趣的朋友一起看看吧2021-06-06
SpringBoot整合MinIO實現(xiàn)文件存儲系統(tǒng)的代碼示例
在現(xiàn)代的應用程序中,文件存儲和管理是一個常見的需求,MinIO是一個開源的對象存儲系統(tǒng),與Spring?Boot框架結合使用,可以快速構建高性能的文件存儲系統(tǒng),本文將介紹如何使用Spring?Boot和MinIO來實現(xiàn)文件存儲系統(tǒng)2023-06-06
Spring Boot 實現(xiàn)Restful webservice服務端示例代碼
這篇文章主要介紹了Spring Boot 實現(xiàn)Restful webservice服務端示例代碼,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-11-11
spring-boot-maven-plugin:unknown的完美解決方法
這篇文章主要介紹了spring-boot-maven-plugin:unknown的完美解決方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11
使用System.exit()來優(yōu)雅地終止SpringBoot項目的代碼示例
System.exit() 方法是 Java 中用于退出程序的方法,它接受一個整數(shù)參數(shù),通常被用來指示程序的退出狀態(tài),本文給大家介紹了如何使用System.exit()來優(yōu)雅地終止SpringBoot項目,需要的朋友可以參考下2024-08-08
postman測試傳入List<String>參數(shù)方式
這篇文章主要介紹了postman測試傳入List<String>參數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
spring的xml文件打開沒有namespace等操作選項的解決方案
這篇文章主要介紹了spring的xml文件打開沒有namespace等操作選項的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

