您好,登錄后才能下訂單哦!
如何正確的結束Java線程?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
使用標志位
很簡單地設置一個標志位,名稱就叫做isCancelled。啟動線程后,定期檢查這個標志位。如果isCancelled=true,那么線程就馬上結束。
public class MyThread implements Runnable{ private volatile boolean isCancelled; public void run(){ while(!isCancelled){ //do something } } public void cancel(){ isCancelled=true; } }
注意的是,isCancelled需要為volatile,保證線程讀取時isCancelled是最新數據。
我以前經常用這種簡單方法,在大多時候也很有效,但并不完善。考慮下,如果線程執行的方法被阻塞,那么如何執行isCancelled的檢查呢?線程有可能永遠不會去檢查標志位,也就卡住了。
使用中斷
Java提供了中斷機制,Thread類下有三個重要方法。
public void interrupt()
public boolean isInterrupted()
public static boolean interrupted(); // 清除中斷標志,并返回原狀態
每個線程都有個boolean類型的中斷狀態。當使用Thread的interrupt()方法時,線程的中斷狀態會被設置為true。
下面的例子啟動了一個線程,循環執行打印一些信息。使用isInterrupted()方法判斷線程是否被中斷,如果是就結束線程。
public class InterruptedExample { public static void main(String[] args) throws Exception { InterruptedExample interruptedExample = new InterruptedExample(); interruptedExample.start(); } public void start() { MyThread myThread = new MyThread(); myThread.start(); try { Thread.sleep(3000); myThread.cancel(); } catch (InterruptedException e) { e.printStackTrace(); } } private class MyThread extends Thread{ @Override public void run() { while (!Thread.currentThread().isInterrupted()) { try { System.out.println("test"); Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("interrupt"); //拋出InterruptedException后中斷標志被清除,標準做法是再次調用interrupt恢復中斷 Thread.currentThread().interrupt(); } } System.out.println("stop"); } public void cancel(){ interrupt(); } } }
對線程調用interrupt()方法,不會真正中斷正在運行的線程,只是發出一個請求,由線程在合適時候結束自己。
例如Thread.sleep這個阻塞方法,接收到中斷請求,會拋出InterruptedException,讓上層代碼處理。這個時候,你可以什么都不做,但等于吞掉了中斷。因為拋出InterruptedException后,中斷標記會被重新設置為false!看sleep()的注釋,也強調了這點。
@throws InterruptedException if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown. public static native void sleep(long millis) throws InterruptedException;
記得這個規則:什么時候都不應該吞掉中斷!每個線程都應該有合適的方法響應中斷!
所以在InterruptedExample例子里,在接收到中斷請求時,標準做法是執行Thread.currentThread().interrupt()恢復中斷,讓線程退出。
從另一方面談起,你不能吞掉中斷,也不能中斷你不熟悉的線程。如果線程沒有響應中斷的方法,你無論調用多少次interrupt()方法,也像泥牛入海。
用Java庫的方法比自己寫的要好
自己手動調用interrupt()方法來中斷程序,OK。但是Java庫提供了一些類來實現中斷,更好更強大。
Executor框架提供了Java線程池的能力,ExecutorService擴展了Executor,提供了管理線程生命周期的關鍵能力。其中,ExecutorService.submit返回了Future對象來描述一個線程任務,它有一個cancel()方法。
下面的例子擴展了上面的InterruptedExample,要求線程在限定時間內得到結果,否則觸發超時停止。
public class InterruptByFuture { public static void main(String[] args) throws Exception { ExecutorService es = Executors.newSingleThreadExecutor(); Future<?> task = es.submit(new MyThread()); try { //限定時間獲取結果 task.get(5, TimeUnit.SECONDS); } catch (TimeoutException e) { //超時觸發線程中止 System.out.println("thread over time"); } catch (ExecutionException e) { throw e; } finally { boolean mayInterruptIfRunning = true; task.cancel(mayInterruptIfRunning); } } private static class MyThread extends Thread { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { try { System.out.println("count"); Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("interrupt"); Thread.currentThread().interrupt(); } } System.out.println("thread stop"); } public void cancel() { interrupt(); } } }
Future的get方法可以傳入時間,如果限定時間內沒有得到結果,將會拋出TimeoutException。此時,可以調用Future的cancel()方法,對任務所在線程發出中斷請求。
cancel()有個參數mayInterruptIfRunning,表示任務是否能夠接收到中斷。
mayInterruptIfRunning=true時,任務如果在某個線程中運行,那么這個線程能夠被中斷;
mayInterruptIfRunning=false時,任務如果還未啟動,就不要運行它,應用于不處理中斷的任務
要注意,mayInterruptIfRunning=true表示線程能接收中斷,但線程是否實現了中斷不得而知。線程要正確響應中斷,才能真正被cancel。
線程池的shutdownNow()會嘗試停止池內所有在執行的線程,原理也是發出中斷請求。
Java的基本數據類型分為:1、整數類型,用來表示整數的數據類型。2、浮點類型,用來表示小數的數據類型。3、字符類型,字符類型的關鍵字是“char”。4、布爾類型,是表示邏輯值的基本數據類型。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。