Java一个线程能否结束另一个永不停止的线程
在Java中停止一個線程有三種辦法?:
1.正常結束執行;
2.發生異常;
3.被其他線程stop(Java官方不建議)
參考:https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
為什么Thread.stop棄用?
 
因為它本質上是不安全的。停止線程會導致它解鎖已鎖定的所有監視器。(當ThreadDeath異常傳播到堆棧中時,監視器將被解鎖。)如果先前受這些監視器保護的任何對象處于不一致狀態,則其他線程現在可以以不一致的狀態查看這些對象。據說這些物體已被?損壞。當線程對受損對象進行操作時,可能會導致任意行為。這種行為可能很微妙并且難以檢測,或者可能是明顯的。與其他未經檢查的異常不同,它會?ThreadDeath默默地殺死線程;?因此,用戶沒有警告他的程序可能被破壞。
?
所以如果遇到一種特殊情況某一個線程A會一直執行下去停不下來,這種情況是存在的比如那種需要持續取樣的線程A,當然了在正常代碼里會有“停止”功能,外部線程B可以發送停止信號給A,A可以直接結束。
如果A線程沒有這種信號量那么B線程還可以主動停止他么?答案是不可以!
public class Test {public static void main(String args[]) throws InterruptedException {Thread thread1 = new Thread() {public void run() {fun_a();}};thread1.start();int a = 0;while (a < 100) {Thread.sleep(1000);a++;if (a == 3) {a = 100;thread1.interrupt();//thread1.stop();//throw new RuntimeException("主函數拋出異常");}}}public static void fun_a() {for (; ; ) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(">> " + DateUtil.getNowTimeString());}}
}
 
 
?可以看到interrupt并不能讓運行中的線程停止,這個是很容易被誤解的地方。這個方法的作用并不是中斷線程,而是設置一個標識,通知該線程可以被中斷了,到底是繼續執行,還是中斷返回,由線程本身自己決定。
當對一個線程調用了interrupt()之后,如果該線程處于被阻塞狀態(比如執行了wait、sleep或join等方法),那么會立即退出阻塞狀態,并拋出一個InterruptedException異常,在代碼中catch這個異常進行后續處理。如果線程一直處于運行狀態,那么只會把該線程的中斷標志設置為 true,僅此而已,所以interrupt()并不能真正的中斷線程,不過在rpc調用的場景中,請求線程一般都處于阻塞狀態,等待數據返回,這時interrupt()方法是可以派上用場的。
參考:Java中如何實現線程的超時中斷
?
修改子線程的代碼:
public static void fun_a() {for (; ; ) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException("子線程拋出異常");//e.printStackTrace();}System.out.println(">> " + DateUtil.getNowTimeString());}} 
這次是可以結束子線程,前提是子線程自己有異常捕獲機制,可以接受其他線程發來的InterruptedException:
?
主線程每隔2秒對子線程進行一次Interrupted:
package com.t.www;public class Test {final static Object lock = new Object();volatile boolean stop = false;public static void main(String args[]) throws InterruptedException {Thread thread1 = new Thread() {public void run() {fun_a();}};thread1.start();System.out.println("> 1 主線程start " + DateUtil.getNowTimeString());int a = 0;while (a < 3) {Thread.sleep(2000);a++;System.out.println("> 2 主線程對子線程開始interrupt " + DateUtil.getNowTimeString());thread1.interrupt();System.out.println("> 3 主線程對子線程完成interrupt " + DateUtil.getNowTimeString());}}public static void fun_a() {for (; ; ) {try {System.out.println(">> 1 子線程wait " + DateUtil.getNowTimeString());synchronized (lock) {lock.wait();}Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException("子線程拋出異常");e.printStackTrace();}System.out.println(">> 2 子線程完成 " + DateUtil.getNowTimeString());}}
}
 
?
?修改子線程代碼:
try {System.out.println(">> 1 子線程wait " + DateUtil.getNowTimeString());synchronized (lock) {lock.wait();}Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException("子線程拋出異常");//e.printStackTrace();System.out.println(">> 2 子線程捕獲異常 " + DateUtil.getNowTimeString());} 
 
從運行結果看和前面一致,只是沒有拋出異常。?
?
修改代碼子線程使用while(!Thread.currentThread().isInterrupted())判斷:
public class Test {public static void main(String args[]) throws InterruptedException {Thread thread1 = new Thread() {public void run() {fun_a();}};thread1.start();System.out.println("> 1 主線程start " + DateUtil.getNowTimeString());int a = 0;while (a < 3) {Thread.sleep(2000);a++;System.out.println("> 2 主線程對子線程開始interrupt " + DateUtil.getNowTimeString());thread1.interrupt();System.out.println("> 3 主線程對子線程完成interrupt " + DateUtil.getNowTimeString());}}public static void fun_a() {while(!Thread.currentThread().isInterrupted()){try {System.out.println(">> 1 子線程 " + DateUtil.getNowTimeString());Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException("子線程拋出異常");//e.printStackTrace();System.out.println(">> 2 子線程捕獲異常 " + DateUtil.getNowTimeString());}System.out.println(">> 3 子線程完成 " + DateUtil.getNowTimeString());}System.out.println(">> 4 子線程正常結束 " + DateUtil.getNowTimeString());}
}
 
可以看到這次因為子線程增加了狀態判斷所以可以正常結束:?
比較優雅的方式是使用一個變量在線程間通信,需要注意的是要保證可見性:
public class Test {private static volatile boolean finished = false;   // ① volatile條件變量public static void main(String args[]) throws InterruptedException {Thread thread1 = new Thread() {public void run() {fun_a();}};thread1.start();System.out.println("> 1 主線程start " + DateUtil.getNowTimeString());int a = 0;while (a < 3) {Thread.sleep(2000);a++;}System.out.println("> 1 主線程 a=" +a+" "+ DateUtil.getNowTimeString());finished=true;}public static void fun_a() {while(!finished){try {System.out.println(">> 1 子線程 " + DateUtil.getNowTimeString());Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException("子線程拋出異常");//e.printStackTrace();System.out.println(">> 2 子線程捕獲異常 " + DateUtil.getNowTimeString());}System.out.println(">> 3 子線程完成 " + DateUtil.getNowTimeString());}System.out.println(">> 4 子線程正常結束 " + DateUtil.getNowTimeString());}
}
 
 
------------------
如何停止線程或任務
?
如何停止一個正在運行的java線程
了解Java中的線程中斷
如何在Java中正確停止Thread?
你如何殺死Java中的線程?
如何在運行時停止/終止長時間運行的Java線程?超時 - >取消 - >中斷狀態
Java - 從不同的類停止線程
https://javaconceptoftheday.com/how-to-stop-a-thread-in-java/
如何超時一個線程
?
參考《Effective Java 中文版 第3版》
總結
以上是生活随笔為你收集整理的Java一个线程能否结束另一个永不停止的线程的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 泰拉瑞亚被折磨的灵魂怎么找?
 - 下一篇: 我的世界多少钱啊?