Java實現(xiàn)優(yōu)雅停止線程的有效方法詳解
在Java中停止線程意味著在完成其任務之前停止正在進行的操作,本質(zhì)上是放棄當前操作。
雖然可以使用 Thread.stop() 方法停止線程,但強烈建議不要這樣做。雖然它確實終止了正在運行的線程,但此方法被認為是不安全的并且已被棄用。
java中終止線程
在Java中,有3種方法可以終止正在運行的線程:
- 使用標志:您可以創(chuàng)建一個boolean類型的標志,線程定期檢查該標志。當該標志設置為某個值時,線程可以優(yōu)雅地退出其執(zhí)行。
- 使用interrupt()方法:可以使用interrupt()方法向線程發(fā)送中斷信號。
- 使用Thread.stop()方法(不推薦):可以使用Thread.stop()方法強行停止正在運行的線程。然而,這種方法不被鼓勵并且被認為是不安全的,因為它可能導致應用程序中出現(xiàn)不可預測為。它已被棄用,應該避免。
interrupt方法
使用interrupt()方法不會像帶有break語句的for循環(huán)一樣立即停止循環(huán)。它會在當前線程內(nèi)設置一個停止標志,但它不會立即停止線程。
public class MyThread extends Thread {
public void run(){
super.run();
for(int i=0; i<500000; i++){
System.out.println("i="+(i+1));
}
}
}
public class Run {
public static void main(String args[]){
Thread thread = new MyThread();
thread.start();
try {
Thread.sleep(2000);
thread.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
結(jié)果:
...
i=499994
i=499995
i=499996
i=499997
i=499998
i=499999
i=500000
*/如何檢查線程是否處于停止狀態(tài)
Java中的提供了兩種方法:
- this.interrupted():該方法檢測當前線程(調(diào)用該方法的線程)是否已被中斷。它還具有清除當前線程的中斷狀態(tài)的作用。
- this.isInterrupted():此方法測試調(diào)用它的線程(不一定是當前線程)是否已被中斷。它不會清除線程的中斷狀態(tài)。
這兩種方法有什么區(qū)別?
我們先看一下this.interrupted()方法:
public class MyThread extends Thread {
public void run(){
super.run();
for(int i=0; i<500000; i++){
i++;
// System.out.println("i="+(i+1));
}
}
}
public class Run {
public static void main(String args[]){
Thread thread = new MyThread();
thread.start();
try {
Thread.sleep(2000);
thread.interrupt();
System.out.println("stop 1??" + thread.interrupted());
System.out.println("stop 2??" + thread.interrupted());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
---------------------------
結(jié)果:
stop 1??false
stop 2??false
*/可以看到 Run 類中調(diào)用Thread對象的 Interrupt() 方法來檢查線程對象的線程是否已停止,控制臺輸出的內(nèi)容表明線程尚未停止。
這也證實了interrupted()方法,它用于檢測當前線程(在此上下文中為主線程)是否已被中斷。由于主線程從未被中斷過,所以打印的結(jié)果是兩個false。
如何讓主線程產(chǎn)生中斷效果
public class Run2 {
public static void main(String args[]){
Thread.currentThread().interrupt();
System.out.println("stop 1??" + Thread.interrupted());
System.out.println("stop 2??" + Thread.interrupted());
System.out.println("End");
}
}
/*
------------------
結(jié)果:
stop 1??true
stop 2??false
End
*/第二個值是 false,因為根據(jù) Interrupted() 方法的官方文檔,它會檢測當前線程(在這里就是主線程)的中斷狀態(tài),它會在調(diào)用時清除線程的中斷狀態(tài)。
換句話說,如果連續(xù)調(diào)用它,第二次調(diào)用返回 false,因為它已經(jīng)清除了第一次調(diào)用設置的中斷狀態(tài)。
因此,如果連續(xù)調(diào)用interrupted()兩次,第二次調(diào)用將返回false,因為第一次調(diào)用清除了線程的中斷狀態(tài)。
isInterrupted()
現(xiàn)在讓我們看一下 isInterrupted() 方法。
public class Run3 {
public static void main(String args[]){
Thread thread = new MyThread();
thread.start();
thread.interrupt();
System.out.println("stop 1??" + thread.isInterrupted());
System.out.println("stop 2??" + thread.isInterrupted());
}
}
/*
---------------
結(jié)果:
stop 1??true
stop 2??true
*/isInterrupted() 不會清除中斷狀態(tài),這就是為什么在輸出中看到兩個true。
使用異常來停止線程
有了上面獲得的知識,就可以在線程中使用for循環(huán)來檢查線程是否處于停止狀態(tài)。 如果處于停止狀態(tài),后續(xù)的代碼將不再運行。
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 500000; i++) {
if (Thread.interrupted()) {
System.out.println("Thread is interrupted. Exiting...");
return; //退出
}
System.out.println("i="+(i+1));
}
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
try {
Thread.sleep(2000);
thread.interrupt(); // 設置中斷狀態(tài)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
-------------
結(jié)果:
...
i=202053
i=202054
i=202055
i=202056
Thread is interrupted. Exiting...
*/在停止線程的同時,將繼續(xù)執(zhí)行 for 循環(huán)之后的任何代碼。
改下代碼,讓我們看一下下面的例子:
public class MyThread extends Thread {
public void run(){
super.run();
for(int i=0; i<500000; i++){
if(this.interrupted()) {
System.out.println("Thread is interrupted. Exiting...");
break;
}
System.out.println("i="+(i+1));
}
System.out.println("Out of for");
}
}
/*
結(jié)果:
...
i=180136
i=180137
i=180138
i=180139
Thread is interrupted. Exiting...
Out of for
*/如何解決中斷后,代碼繼續(xù)執(zhí)行的問題
public class MyThread extends Thread {
public void run(){
super.run();
try {
for(int i=0; i< 500000; i++){
if(this.interrupted()) {
System.out.println("Thread is interrupted. Exiting...");
throw new InterruptedException();
}
System.out.println("i="+(i+1));
}
System.out.println("Out of for");
} catch (InterruptedException e) {
System.out.println("In catch...");
e.printStackTrace();
}
}
}
/*
--------------------------------------------------------------------------
結(jié)果:
...
i=203798
i=203799
i=203800
Thread is interrupted. Exiting...
In catch...
java.lang.InterruptedException
at thread.MyThread.run(MyThread.java:13)
*/線程Sleep怎么停止
如果線程在 sleep() 狀態(tài)下停止會有什么影響?
public class MyThread extends Thread {
public void run(){
super.run();
try {
System.out.println("Thread begin...");
Thread.sleep(200000);
System.out.println("Thread end...");
} catch (InterruptedException e) {
System.out.println("Stop while sleeping" + this.isInterrupted());
e.printStackTrace();
}
}
}
/*
-----------------------------------------------------------------------
結(jié)果:
Thread begin...
Stop while sleeping,the result of isInterrupted() is::false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at thread.MyThread.run(MyThread.java:12)
*/從打印結(jié)果來看,如果線程在睡眠狀態(tài)下停止,它將拋出InterruptedException異常進入catch塊并清除停止狀態(tài)值,將其設置為false。
強制停止線程
使用 stop() 方法終止線程是一種非常激進的方法。
public class MyThread extends Thread {
private int i = 0;
public void run(){
super.run();
try {
while (true){
System.out.println("i=" + i);
i++;
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Run {
public static void main(String args[]) throws InterruptedException {
Thread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.stop();
}
}
/*
-----------------------------------------------
結(jié)果:
i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
Process finished with exit code 0
*/當調(diào)用 stop() 方法時,它會拋出 java.lang.ThreadDeath 異常,但大多數(shù)情況下,不需要顯式捕獲該異常。
public class MyThread extends Thread {
private int i = 0;
public void run(){
super.run();
try {
this.stop();
} catch (ThreadDeath e) {
System.out.println("In catch");
e.printStackTrace();
}
}
}
public class Run {
public static void main(String args[]) throws InterruptedException {
Thread thread = new MyThread();
thread.start();
}
}
stop() 方法已被棄用,因為強制停止線程可能會阻止某些必要的清理工作完成。
此外,它還可能導致鎖定對象解鎖,從而導致數(shù)據(jù)同步問題和數(shù)據(jù)不一致問題。 由
于 stop() 方法在 JDK 中已被標記為已棄用/過時,因此很明顯它存在功能缺陷。 因此,不建議在程序中使用 stop() 方法。
使用 return 來停止線程
將interrupt()方法與return結(jié)合起來也可以達到停止線程的效果。
public class MyThread extends Thread {
public void run(){
while (true){
if(this.isInterrupted()){
System.out.println("The thread has been stopped.");
return;
}
System.out.println("Time: " + System.currentTimeMillis());
}
}
}
public class Run {
public static void main(String args[]) throws InterruptedException {
Thread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
}
}
/*
------------------------------------
結(jié)果:...
Time: 1696990194000
Time: 1696990194000
Time: 1696990194000
The thread has been stopped.
*/但是,仍然建議使用“拋出異常”方法來停止線程,因為它允許您通過在 catch 塊中重新拋出異常來傳播停止事件。
到此這篇關(guān)于Java實現(xiàn)優(yōu)雅停止線程的有效方法詳解的文章就介紹到這了,更多相關(guān)Java停止線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaWeb基礎(chǔ)概念以及與架構(gòu)之間有哪些區(qū)別
JavaWeb是基于Java技術(shù)棧開發(fā)的Web應用,SpringMVC是實現(xiàn)JavaWeb的一種框架,C/S架構(gòu)和B/S架構(gòu)的區(qū)別主要在客戶端形式、開發(fā)維護成本、響應速度和跨平臺能力,本文介紹JavaWeb基礎(chǔ)概念以及與架構(gòu)之間有哪些區(qū)別,感興趣的朋友跟隨小編一起看看吧2025-12-12
SpringBoot2.0整合jackson配置日期格式化和反序列化的實現(xiàn)
這篇文章主要介紹了SpringBoot2.0整合jackson配置日期格式化和反序列化的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11
spring?boot?mybatis日志輸出到控制臺的方法實踐
在開發(fā)過程中我們往往需要打印出SQL語句,這樣就方便我們監(jiān)控問題,本文主要介紹了spring?boot?mybatis日志輸出到控制臺的方法實踐,具有一定的參考價值,感興趣的可以了解一下2024-05-05
Springmvc 4.x利用@ResponseBody返回Json數(shù)據(jù)的方法
這篇文章主要介紹了Springmvc 4.x利用@ResponseBody返回Json數(shù)據(jù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
java根據(jù)擴展名獲取系統(tǒng)圖標和文件圖標示例
這篇文章主要介紹了java根據(jù)擴展名獲取系統(tǒng)圖標和文件圖標示例,需要的朋友可以參考下2014-03-03
Spring Boot與Spring Security的跨域問題解決方案
跨域問題是指在Web開發(fā)中,瀏覽器出于安全考慮,限制了不同域名之間的資源訪問,本文重點給大家介紹Spring Boot與Spring Security的跨域問題解決方案,感興趣的朋友一起看看吧2023-09-09

