多線程編程中耗時線程是很常見的情況,有時候我們不得不在一個線程中去終止另一個耗時線程。JDK並不推薦直接停止比如this.stop(),這會導致一些異常,比如鎖未釋放程序一直死鎖。JDK推薦使用一個線程去通知耗時線程該結束線程了,耗時線程做退出前的回收處理然后自己結束線程。
自定義標志位終止
使用volatile 修飾的變量isExit控制線程的退出,這種方法需要不斷及時判斷isExit的值
public class FinishThreadLearn { public static void main(String[] args) throws InterruptedException { InterruptStopThread threadA = new InterruptStopThread("A"); threadA.start(); Thread.sleep(100); System.out.println("終止線程"); threadA.isExit=true; } } class InterruptStopThread extends Thread { private String name; public volatile boolean isExit = false; public InterruptStopThread(String name) { this.name = name; } @Override public void run() { super.run(); while (!isExit) { System.out.println("Thead:" + this.name + "正在運行"); } System.out.println("線程結束運行"); } }
輸出結果可以看到,線程並未立即終止,結束循環體后才最終結束線程。
interrupt() 方式終止
正常執行的代碼
public class FinishThreadLearn { public static void main(String[] args) throws InterruptedException { InterruptStopThread threadA = new InterruptStopThread("A"); threadA.start(); Thread.sleep(100); System.out.println("終止線程"); threadA.interrupt(); } } class InterruptStopThread extends Thread { private String name; public volatile boolean isExit = false; public InterruptStopThread(String name) { this.name = name; } @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("Thead:" + this.name + "正在運行"); } System.out.println("線程結束運行"); } }
執行結果
處於阻塞休眠的代碼
這里有點不一樣,interrupt()方式中斷阻塞會把標志位清除並報出InterruptedException異常,所以要在catch的時候退出。
public class FinishThreadLearn { public static void main(String[] args) throws InterruptedException { InterruptStopThread threadA = new InterruptStopThread("A"); threadA.start(); Thread.sleep(2000); System.out.println("終止線程"); threadA.interrupt(); } } class InterruptStopThread extends Thread { private String name; public volatile boolean isExit = false; public InterruptStopThread(String name) { this.name = name; } @Override public void run() { super.run(); while (true) { System.out.println("Thead:" + this.name + "正在運行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); break; } } System.out.println("線程結束運行"); } }
執行結果
stop()強行停止
public class FinishThreadLearn { public static void main(String[] args) throws InterruptedException { InterruptStopThread threadA = new InterruptStopThread("A"); threadA.start(); Thread.sleep(100); System.out.println("終止線程"); threadA.stop(); } } class InterruptStopThread extends Thread { private String name; public volatile boolean isExit = false; public InterruptStopThread(String name) { this.name = name; } @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("Thead:" + this.name + "正在運行"); } System.out.println("線程結束運行"); } }
從執行結果可以看到,run方法並未完全執行完就結束了,所以這種方法不推薦使用
源碼分析
Thread源碼中使用了一個volatile修飾的標志位控制終止信號
public class Thread implements Runnable { ... /* Interrupt state of the thread - read/written directly by JVM */ private volatile boolean interrupted; ... }
interrupt方法會使標志位變為true
判斷線程是否終止JDK提供了兩種方式
Thread.interrupted():測試當前線程是否已經中斷 this.isInterrupted():測試線程是否已經中斷
this.isInterrupted()
調用isInterrupted會返回該標志位
Thread.interrupted()
調用interrupted會返回該標志位,如果為ture會將標志位清空,且這個方法為靜態方法