標籤:api tab exit bsp 線程 遞迴調用 art dex print
三、中斷一個線程
一個擁有多個線程的Java程式要結束,需要滿足兩個條件之一:一是所有的非後台線程都執行結束了;二是某個線程執行了 System.exit() 方法。當你想要終結一個運行中的Java程式或者程式的使用者想要取消一個線程正在執行的任務時,你都需要結束一個線程。
Java提供中斷機制來表明我們想要終止一個線程。這個機制的核心是線程必須要檢查自己是否被中斷,而且線程自己決定是否響應插斷要求。線程可以忽略該插斷要求而繼續執行。
在本秘訣中,我們將開發一個程式,這個程式建立線程,5秒後使用中斷機制來結束線程。
public class Main { public static void main(String[] args) { Thread task = new PrimeGenerator(); task.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } task.interrupt(); }}public class PrimeGenerator extends Thread { @Override public void run() { long number = 1L; while (true) { if (isPrime(number)) { System.out.printf("Number "+ number +" is Prime"); } if (isInterrupted()) { System.out.printf("The Prime Generator has been Interrupted"); return; } number++; } } private boolean isPrime(long number) { if (number <= 2) { return true; } for (long i = 2; i < number; i++) { if ((number % i) == 0) { return false; } } return true; }}
在 Thread 類中有一個 boolean 類型的屬性來表明該類對應的線程是否被中斷。通過調用 Thread 對象的 interrupt() 方法,設定其對應的線程被中斷。而 isInterrupted() 方法用來返回對應線程是否被中斷的狀態。
Thread 類還有一個靜態方法 interrupted() 同樣可以返回所線上程是否被中斷的狀態。但是該方法還有一個副作用:就是把線程的被中斷狀態重設為 false。
線程可以忽略其被中斷的狀態,但這通常不是好的編程習慣。
四、控制線程的中斷狀態
在上一個秘訣中,你學習了如何去中斷一個線程和如何去控制線程的中斷狀態。如果你要中斷執行的只是一個簡單的線程,那麼上一個秘訣就足夠了。但是,如果該線程實現了一個分成多個方法的複雜演算法,或者它含有實現了遞迴演算法的方法,我們應該使用一種更好的機制去該線程的中斷狀態。為此,Java提供了 InterruptedException。當你在 run() 方法裡發現了線程被中斷時,你可以拋出並捕獲該異常。
在本秘訣中,我們的線程在目錄和其子目錄中來尋找含有特定名稱的檔案,這個程式展示如何使用 InterruptedException 來控制線程的中斷。
public class FileSearch implements Runnable{ private String initPath; private String fileName; public FileSearch(String initPath, String fileName) { this.initPath = initPath; this.fileName = fileName; } @Override public void run() { File file = new File(initPath); if (file.isDirectory()) { try { directoryProcess(file); } catch (InterruptedException e) { System.out.printf("%s: The search has been " + "interrupted", Thread.currentThread().getName()); } } } private void directoryProcess(File file) throws InterruptedException { File list[] = file.listFiles(); if (list != null) { for (int i = 0; i < list.length; i++) { if (list[i].isDirectory()) { directoryProcess(list[i]); } else { fileProcess(list[i]); } } } if (Thread.interrupted()) { throw new InterruptedException(); } } private void fileProcess(File file) throws InterruptedException { if (file.getName().equals(fileName)) { System.out.printf("%s : %s\n", Thread.currentThread().getName(), file.getAbsolutePath()); } if (Thread.interrupted()) { throw new InterruptedException(); } }}public class Main { public static void main(String[] args) { FileSearch search = new FileSearch("C:\\", "autoexec.bat"); Thread thread = new Thread(search); thread.start(); try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); }}
在這個例子中,我們使用異常機制來達到終止線程啟動並執行目的。你運行此樣本程式,程式開始遍曆目錄並尋找特定的檔案。一旦線程檢查到自己被中斷了,它就拋出 InterruptedException 異常,繼續執行 run() 方法的代碼,多層的遞迴調用對結果沒實質影響。
Java並發API中的 sleep() 方法也有可能拋出 InterruptedException異常。
筆者總結:本秘訣本質還是線程自己檢查是否被中斷,發現被中斷後,通過拋出異常的方式直接跳轉到了異常捕獲代碼處,是否多層遞迴對此異常跳轉機制沒影響。
重要:本系列翻譯文檔也會在本人的公眾號(此山是我開)第一時間發布,歡迎大家關注。
Java 7 Concurrency Cookbook 翻譯 第一章 線程管理之二