首先說明,使用stop方法終止的方式已經在很久之前就被廢棄了,在加鎖的情況下有可能會造成死鎖,這里不做討論。
1. 使用標志位終止線程
在run()方法執行完畢后,該線程就終止了。但是在某些特殊的情況下,希望run()方法中的代碼一直循環執行。比如在服務端程序中可能會使用 while(true) { ... } 這樣的循環結構來不斷的接收來自客戶端的請求。此時就可以用修改標志位的方式來結束 run() 方法。例:
public class ServerThread extends Thread { //volatile修飾符用來保證其它線程讀取的總是該變量的最新的值 public volatile boolean exit = false; @Override public void run() { ServerSocket serverSocket = new ServerSocket(8080); while(!exit){ serverSocket.accept(); //阻塞等待客戶端消息 ... } } public static void main(String[] args) { ServerThread t = new ServerThread(); t.start(); ... t.exit = true; //修改標志位,退出線程 } }
Note:一定要給標志位加上volatle 關鍵字!詳細原因可參考:https://www.cnblogs.com/yongdaimi/p/9566332.html 或者 https://www.cnblogs.com/dolphin0520/p/3920373.html 。
2. 使用interrupt()方法來終止線程
interrupt()方法用於中斷線程,調用該方法的線程狀態將會被置為“中斷狀態”。
Note: 線程中斷僅僅是置線程的中斷狀態位,不會停止線程。需要用戶自己去監視線程的狀態為並做處理。java中的那些支持線程中斷的方法(也就是線程中斷后會拋出interruptedException的方法)就是在監視線程的中斷狀態,一旦線程的中斷狀態被置為“中斷狀態”,就會拋出中斷異常。
調用這種方式去終止的線程存在兩種情況:
第一種情況:該線程循環執行不會存在阻塞
比如,在while 循環中循環打印一句話:這樣的話調用interrupt()會立即終止該線程。例:
package com.yongdaimi.java.demo; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Test3 { public static void main(String[] args) { NotInterruptThread mNotInterruptThread = new NotInterruptThread(); mNotInterruptThread.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } mNotInterruptThread.interrupt(); } static class NotInterruptThread extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("=============NotInterruptThread execute... ============="); } } } }
運行結果:
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
5 秒后,打印就會停止。
第二種情況:該線程循環執行存在阻塞狀態
比如,在線程中存在sleep()、await()、wait(long) 這種能夠拋出:interruptedException 異常的方法,這種情況調用interrupt()方法后將會觸發這些異常,可以選擇在觸發異常后調用break來終止線程。例:
package com.yongdaimi.java.demo; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Test3 { private static Object sLock = new Object(); private static ReentrantLock sReentrantLock = new ReentrantLock(); private static Condition sSuspendCondition = sReentrantLock.newCondition(); public static void main(String[] args) { /*NotInterruptThread mNotInterruptThread = new NotInterruptThread(); mNotInterruptThread.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } mNotInterruptThread.interrupt(); */ InterruptThread interruptThread = new InterruptThread(); interruptThread.start(); try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } interruptThread.interrupt(); /*InterruptThread1 interruptThread1 = new InterruptThread1(); interruptThread1.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } interruptThread1.interrupt();*/ /*InterruptThread2 interruptThread2 = new InterruptThread2(); interruptThread2.start(); try { Thread.sleep(3000); } catch (InterruptedException e1) { e1.printStackTrace(); } interruptThread2.interrupt();*/ /*sReentrantLock.lock(); try { sSuspendCondition.signal(); } catch (Exception e) { e.printStackTrace(); } finally { sReentrantLock.unlock(); }*/ } static class NotInterruptThread extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("=============NotInterruptThread execute... ============="); } } } static class InterruptThread extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { System.out.println("=============InterruptThread execute... ============="); try { Thread.sleep(50000); } catch (InterruptedException e) { e.printStackTrace(); break; } } } } static class InterruptThread1 extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { synchronized (sLock) { System.out.println("=============InterruptThread execute... ============="); try { sLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); break; } } } } } static class InterruptThread2 extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { sReentrantLock.lock(); try { System.out.println("=============InterruptThread execute... ============="); sSuspendCondition.await(); } catch (InterruptedException e) { e.printStackTrace(); break; } finally { sReentrantLock.unlock(); } } } } }
我這里分別演示了使用sleep()、wait()、await()的方式來阻塞線程,然后在主線程休眠一段時間后嘗試去中斷,子線程中收到異常后調用break退出循環,實際試驗都可以正常退出循環。
參考鏈接:
1. interrupt、interrupted 、isInterrupted 區別
