在上篇文章Java併發編程之線程篇之線程簡介(二)中咱們基本瞭解瞭如何建立一個線程並執行相應任務,可是並無提到如何中斷一個線程。例如:咱們有一個下載程序線程,該線程在沒有下載成功以前是不會退出的,假如這個時候用戶不想下載了,那咱們該如何中斷這個下載線程呢?下面咱們就來學習如何正確的中斷一個線程吧。java
對於過期的suspend()、resume()和stop()方法,這裏就不介紹了,有興趣的小夥伴能夠查閱相關資料。編程
當咱們須要中斷某個線程時,看似咱們只須要調一箇中斷方法(調用以後線程就不執行了)就好了。可是Java中並無提供一個實際的方法來中斷某個線程(不考慮過期的stop()方法),只提供了一箇中斷標誌位,來表示線程在運行期間已經被其餘線程進行了中斷操做。也就是說線程只有經過自身來檢查這個標誌位,來判斷本身是否被中斷了。在Java中提供了三個方法來設置或判斷中斷標誌位,具體方法以下所示:markdown
//類方法,設置當前線程中標誌位 public void interrupt() { if (this != Thread.currentThread()) checkAccess(); synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { interrupt0(); // 設置中斷標誌位 b.interrupt(this); return; } } interrupt0();//設置中斷標誌位 } //靜態方法,判斷當前線程是否中斷,清除中斷標誌位 public static boolean interrupted() { return currentThread().isInterrupted(true); } //類方法,判斷當前線程是否中斷,不清除中斷標誌位 public boolean isInterrupted() { return isInterrupted(false); } 複製代碼
在上述方法中,咱們能夠經過interrupt()
來設置相應線程中斷標誌,經過Thread類靜態方法interrupted()
和類方法isInterrupted()
來判斷對應線程是否被其餘線程中斷。併發
其中interrupted()與isInterrupted()方法的主要區別以下:ide
interrupted
判斷當前線程是否中斷(若是是中斷,則會清除中斷的狀態標誌,也就是若是中斷了線程,第一次調用這個方法返回true,第二次繼續調用則返回false。isInterrupted
判斷線程是否已經中斷(不清除中斷的狀態標誌)。在上文中,咱們瞭解了線程的如何設置中斷標誌位與如何判斷標誌位,那如今咱們來使用interrupt()
方法來中斷一個線程。先看下面這個例子。post
class InterruptDemo { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000000; i++) { System.out.println("i=" + i); } } }); thread.start(); try { Thread.sleep(2000); thread.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } } //輸出結果: i=593210 i=593211 i=593212 i=593213 i=593214 i=593215 i=593216 複製代碼
運行上述代碼,觀察輸出結果,咱們發現線程並無被終止,緣由是由於interrupt()方法只會設置線程中斷標誌位,並不會真正的中斷線程
。也就是說咱們只有本身來判斷線程是否終止。通常狀況下,當咱們檢查到線程被中斷(也就是線程標誌位爲true)時,會拋出一個InterruptedException
異常,來中斷線程任務。具體代碼以下:學習
class InterruptDemo { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { try { for (int i = 0; i < 1000000; i++) { if (Thread.interrupted()) { System.out.println("檢測到線程被中斷"); throw new InterruptedException(); } System.out.println("i=" + i); } } catch (InterruptedException e) { //執行你本身的中斷邏輯 System.out.println("線程被中斷了,你本身判斷該如何處理吧"); e.printStackTrace(); } } }); thread.start(); try { Thread.sleep(2000); thread.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } } //輸出結果: i=218626 i=218627 i=218628 i=218629 i=218630 檢測到線程被中斷 線程被中斷了,你本身判斷該如何處理吧 java.lang.InterruptedException at InterruptDemo$1.run(InterruptDemo.java:18) at java.base/java.lang.Thread.run(Thread.java:835) 複製代碼
在上述代碼中,咱們經過在線程中判斷Thread.interrupted()
來判斷線程是否中斷,當線程被中斷後,咱們拋出InterruptedException異常。而後經過try/catch來捕獲該異常來執行咱們本身的中斷邏輯。固然咱們也能夠經過Thread.currentThread().isInterrupted()
來判斷。這兩個方法的區別已經在上文介紹了,這裏就不過多的介紹了。this
在上文中提到的使用interrupt()來中斷線程之外,咱們還能夠經過一個boolean來控制是否中斷線程。具體例子以下所示:spa
class InterruptDemo { public static void main(String[] args) { RunnableA runnableA = new RunnableA(); Thread thread = new Thread(runnableA); thread.start(); try { Thread.sleep(2000); runnableA.interruptThread(); } catch (InterruptedException e) { e.printStackTrace(); } } static class RunnableA implements Runnable { boolean isInterrupt; @Override public void run() { for (int i = 0; i < 1000000; i++) { if (!isInterrupt) { System.out.println("i=" + i); } else { System.out.println("線程結束運行了"); break; } } } void interruptThread() { isInterrupt = true; } } } //輸出結果: i=240399 i=240400 i=240401 i=240402 i=240403 i=240404 i=240405 線程結束運行了 複製代碼
上述代碼中,咱們經過判斷isInterrupt
的值來判斷是否跳出循環。run()方法的結束,就標誌着線程已經執行完畢了。線程
站在巨人的肩膀上,才能看的更遠~