線程的中斷條件java
- 當線程的run方法執行方法中的最後一句話後,並由return語句返回時,線程結束 2. 或是在線程中出現了沒有捕獲的異常時,線程將終止 3. interrupt方法能夠用來請求終止線程 interrupt
- 爲何要用interrupt來中斷線程,在什麼狀況下用 interrupt是用來強制中斷那些出於阻塞狀態(sleep,join,wait)的線程,阻塞狀態的線程被調用interrupt時會拋出InterruptException 的錯誤,而後退出阻塞狀態,這個錯誤要被catch才行。 若是線程再調用interrupt時,不處於阻塞狀態,則在線程進入阻塞狀態時,會拋出InterruptException
- interrupt 說明 主要來講明下interrupt,若是對一個線程調用interrupt方法時,線程的中斷狀態將被置位,也就是改變線程的中斷狀態,由於每一個線程都有一個boolean標誌,每一個線程都會不時的檢查標誌來判斷是否被中斷。
public class threadInterrupt {異步
public static void main(String[] args) { final Thread aThread = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println(" thread a throw interruptException "); } } }); aThread.setName("aaaaaaaaaa"); Thread bThread = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub System.out.println("interrupt 前的中斷標誌"+aThread.isInterrupted() ); aThread.interrupt(); System.out.println("interrupt 後的中斷標誌"+aThread.isInterrupted() ); } }); aThread.start(); bThread.start(); }
}socket
圖片中能夠看到在調用interrupt前的false ,調用interrupt後是true 並拋出了interruptExceptionide
static boolean interrupted() 用來測試線程是否被中斷,可是會將線程的中斷狀態改成false boolean isInterrupted() 也是用來測試線程是否被終止,但不會改變中斷狀態函數
###對中斷操做的正確理解 調用interrupt 並不意味着當即中止目標線程在進行的工做,而只是傳遞了請求中斷的消息,而後由線程在下一個合適的時刻中斷本身。例如wait、slepp和join等,當他們接收到中斷請求或者在開始執行時發現某個已經被設置好的中斷狀態時,將拋出一個異常。 > 一般中斷是實現取消的最合理方式測試
例如用下面兩個例子來講明,爲何中斷是取消的最合理的方式 (1)首先是不採用中斷的方式來取消,加入下面queue的長度是5,在添加第6個元素時,queue.put()會產生阻塞,因此在以後的時間裏,線程是不會去檢測cancelled的標誌,因此任務永遠也不會結束,這樣就沒法取消了this
class BrokenPrimeProducer extends Thread { private final BlockingQueue<BigInteger> queue; private volatile boolean cancelled = false; BrokenPrimeProducer(BlockingQueue<BigInteger> queue) { this.queue = queue; } public void run() { try { BigInteger p = BigInteger.ONE; while (!cancelled) queue.put(p = p.nextProbablePrime()); } catch (InterruptedException consumed) { } } public void cancel() { cancelled = true; } }
(2)下面這個是用中斷來取消,由於Thread.sleep、Object.wait或BlockingQueue.put等阻塞函數都會檢查線程合適中斷,而且發現中斷就提早返回,執行的操做包括清楚中斷狀態,拋出InterruptedException。在阻塞操做前檢查線程的阻塞狀態能夠提升對中斷操做的響應。線程
public class PrimeProducer extends Thread { private final BlockingQueue<BigInteger> queue; PrimeProducer(BlockingQueue<BigInteger> queue) { this.queue = queue; } public void run() { try { BigInteger p = BigInteger.ONE; while (!Thread.currentThread().isInterrupted()) queue.put(p = p.nextProbablePrime()); } catch (InterruptedException consumed) { /* Allow thread to exit */ } } public void cancel() { interrupt(); } }
線程任務的取消
一般,使用現有庫中的類逼本身編寫的來取消線程任務要來的更好,英雌咱們應該用Future來取消一個線程任務。code
public class TimedRun { private static final ExecutorService taskExec = Executors.newCachedThreadPool(); public static void timedRun(Runnable r, long timeout, TimeUnit unit) throws InterruptedException { Future<?> task = taskExec.submit(r); try { task.get(timeout, unit); } catch (TimeoutException e) { // 任務將被取消 } catch (ExecutionException e) { // 若是在任務中拋出了異常,那麼從新拋出該異常 throw LaunderThrowable.launderThrowable(e.getCause()); } finally { // 若是任務已經結束,那麼執行取消操做也不會帶來什麼影響 task.cancel(true); // interrupt if running } } }
對於不可中斷阻塞的處理
對於某些線程阻塞操做,並不會拋出InterruptedException 例如某些I/O操做和內部鎖操做圖片
- Java.io包中的同步SocketI/O. 讀寫socket的時候,InputStream和OutputStream的read和write方法會阻塞等待,但不會響應java中斷。不過,調用Socket的close方法後,被阻塞線程會拋出SocketException異常。
- Selector實現的異步I/O 若是線程被阻塞於Selector.select(在java.nio.channels中),那麼調用wakeup或close方法會引發ClosedSelectorException異常。
- 獲取某個鎖 若是一個線程因爲等待某個內置鎖而阻塞,那麼將沒法響應中斷,由於線程認爲它確定會得到鎖,因此不會理會中斷請求。