理解java執行緒的中斷(interrupt)
一個執行緒在未正常結束之前, 被強制終止是很危險的事情. 因為它可能帶來完全預料不到的嚴重後果比如會帶著自己所持有的鎖而永遠的休眠,遲遲不歸還鎖等。 所以你看到Thread.suspend, Thread.stop等方法都被Deprecated了
那麼不能直接把一個執行緒搞掛掉, 但有時候又有必要讓一個執行緒死掉, 或者讓它結束某種等待的狀態 該怎麼辦呢?一個比較優雅而安全的做法是:使用等待/通知機制或者給那個執行緒一箇中斷訊號, 讓它自己決定該怎麼辦。
等待/通過機制在另一篇部落格中詳細的介紹了。這裡我們理解執行緒中斷的使用場景和使用時的注意事項,最後使用Demo來理解。
中斷執行緒的使用場景:
在某個子執行緒中為了等待一些特定條件的到來, 你呼叫了Thread.sleep(10000), 預期執行緒睡10秒之後自己醒來, 但是如果這個特定條件提前到來的話, 來通知一個處於Sleep的執行緒。又比如說.執行緒通過呼叫子執行緒的join方法阻塞自己以等待子執行緒結束, 但是子執行緒執行過程中發現自己沒辦法在短時間內結束, 於是它需要想辦法告訴主執行緒別等我了. 這些情況下, 就需要中斷.
斷是通過呼叫Thread.interrupt()方法來做的. 這個方法通過修改了被呼叫執行緒的中斷狀態來告知那個執行緒, 說它被中斷了. 對於非阻塞中的執行緒, 只是改變了中斷狀態, 即Thread.isInterrupted()將返回true; 對於可取消的阻塞狀態中的執行緒, 比如等待在這些函式上的執行緒, Thread.sleep(), Object.wait(), Thread.join(), 這個執行緒收到中斷訊號後, 會丟擲InterruptedException, 同時會把中斷狀態置回為true.但呼叫Thread.interrupted()會對中斷狀態進行復位。
對非阻塞中的執行緒中斷的Demo:
public class Thread3 extends Thread{
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Someone interrupted me.");
}
else{
System.out.println("Thread is Going..." );
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread3 t = new Thread3();
t.start();
Thread.sleep(3000);
t.interrupt();
}
}
分析如上程式的結果:
在main執行緒sleep的過程中由於t執行緒中isInterrupted()為false所以不斷的輸出”Thread is going”。當呼叫t執行緒的interrupt()後t執行緒中isInterrupted()為true。此時會輸出Someone interrupted me.而且執行緒並不會因為中斷訊號而停止執行。因為它只是被修改一箇中斷訊號而已。
首先我們看看interrupt究竟在幹什麼。
當我們呼叫t.interrput()的時候,執行緒t的中斷狀態(interrupted status) 會被置位。我們可以通過Thread.currentThread().isInterrupted() 來檢查這個布林型的中斷狀態。
在Core Java中有這樣一句話:”沒有任何語言方面的需求要求一個被中斷的程式應該終止。中斷一個執行緒只是為了引起該執行緒的注意,被中斷執行緒可以決定如何應對中斷 “。好好體會這句話的含義,看看下面的程式碼:
//Interrupted的經典使用程式碼
public void run(){
try{
....
while(!Thread.currentThread().isInterrupted()&& more work to do){
// do more work;
}
}catch(InterruptedException e){
// thread was interrupted during sleep or wait
}
finally{
// cleanup, if required
}
}
很顯然,在上面程式碼中,while迴圈有一個決定因素就是需要不停的檢查自己的中斷狀態。當外部執行緒呼叫該執行緒的interrupt 時,使得中斷狀態置位即變為true。這是該執行緒將終止迴圈,不在執行迴圈中的do more work了。
這說明: interrupt中斷的是執行緒的某一部分業務邏輯,前提是執行緒需要檢查自己的中斷狀態(isInterrupted())。
但是當執行緒被阻塞的時候,比如被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞時。呼叫它的interrput()方法。可想而知,沒有佔用CPU執行的執行緒是不可能給自己的中斷狀態置位的。這就會產生一個InterruptedException異常。
/*
* 如果執行緒被阻塞,它便不能核查共享變數,也就不能停止。這在許多情況下會發生,例如呼叫
* Object.wait()、ServerSocket.accept()和DatagramSocket.receive()時,他們都可能永
* 久的阻塞執行緒。即使發生超時,在超時期滿之前持續等待也是不可行和不適當的,所以,要使
* 用某種機制使得執行緒更早地退出被阻塞的狀態。很不幸運,不存在這樣一種機制對所有的情況
* 都適用,但是,根據情況不同卻可以使用特定的技術。使用Thread.interrupt()中斷執行緒正
* 如Example1中所描述的,Thread.interrupt()方法不會中斷一個正在執行的執行緒。這一方法
* 實際上完成的是,線上程受到阻塞時丟擲一箇中斷訊號,這樣執行緒就得以退出阻塞的狀態。更
* 確切的說,如果執行緒被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,那麼,
* 它將接收到一箇中斷異常(InterruptedException),從而提早地終結被阻塞狀態。因此,
* 如果執行緒被上述幾種方法阻塞,正確的停止執行緒方式是設定共享變數,並呼叫interrupt()(注
* 意變數應該先設定)。如果執行緒沒有被阻塞,這時呼叫interrupt()將不起作用;否則,執行緒就
* 將得到異常(該執行緒必須事先預備好處理此狀況),接著逃離阻塞狀態。在任何一種情況中,最
* 後執行緒都將檢查共享變數然後再停止。下面示例描述了該技術。
* */
package Concurrency.Interrupt;
class Example3 extends Thread {
volatile boolean stop = false;
public static void main(String args[]) throws Exception {
Example3 thread = new Example3();
System.out.println("Starting thread...");
thread.start();
Thread.sleep(3000);
System.out.println("Asking thread to stop...");
/*
* 如果執行緒阻塞,將不會檢查此變數,呼叫interrupt之後,執行緒就可以儘早的終結被阻
* 塞狀 態,能夠檢查這一變數。
* */
thread.stop = true;
/*
* 這一方法實際上完成的是,線上程受到阻塞時丟擲一箇中斷訊號,這樣執行緒就得以退
* 出阻 塞的狀態
* */
thread.interrupt();
Thread.sleep(3000);
System.out.println("Stopping application...");
System.exit(0);
}
public void run() {
while (!stop) {
System.out.println("Thread running...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// 接收到一箇中斷異常(InterruptedException),從而提早地終結被阻塞狀態
System.out.println("Thread interrupted...");
}
}
System.out.println("Thread exiting under request...");
}
}
/*
* 把握幾個重點:stop變數、run方法中的sleep()、interrupt()、InterruptedException。串接起
* 來就是這個意思:當我們在run方法中呼叫sleep(或其他阻塞執行緒的方法)時,如果執行緒阻塞的
* 時間過長,比如10s,那在這10s內,執行緒阻塞,run方法不被執行,但是如果在這10s內,stop被
* 設定成true,表明要終止這個執行緒,但是,現線上程是阻塞的,它的run方法不能執行,自然也就
* 不能檢查stop,所 以執行緒不能終止,這個時候,我們就可以用interrupt()方法了:我們在
* thread.stop = true;語句後呼叫thread.interrupt()方法, 該方法將線上程阻塞時丟擲一箇中斷
* 訊號,該訊號將被catch語句捕獲到,一旦捕獲到這個訊號,執行緒就提前終結自己的阻塞狀態,這
* 樣,它就能夠 再次執行run 方法了,然後檢查到stop = true,while迴圈就不會再被執行,在執
* 行了while後面的清理工作之後,run方法執行完 畢,執行緒終止。
* */
當代碼呼叫中須要丟擲一個InterruptedException, 你可以選擇把中斷狀態復位, 也可以選擇向外丟擲InterruptedException, 由外層的呼叫者來決定.
不是所有的阻塞方法收到中斷後都可以取消阻塞狀態, 輸入和輸出流類會阻塞等待 I/O 完成,但是它們不丟擲 InterruptedException,而且在被中斷的情況下也不會退出阻塞狀態.
嘗試獲取一個內部鎖的操作(進入一個 synchronized 塊)是不能被中斷的,但是 ReentrantLock 支援可中斷的獲取模式即 tryLock(long time, TimeUnit unit)。
相關推薦
Java 執行緒中斷(interrupt)與阻塞 (park)的區別
很多Java開發人員(包括我),尤其是剛進入軟體行業的新手,認為Java設定執行緒中斷就是表示執行緒停止了,不往前執行了, Thread.currentThread().interrupt() 其實不是這樣的,執行緒中斷只是一個狀態而已,true表示已
JAVA 執行緒中斷interrupt()
執行緒中斷有三種方法: 1、stop(),暴力中斷,會導致事物不完整,已被廢棄 2、flag標記法,用標記變數做迴圈條件,外部執行緒改變flag的值來達到中斷執行緒的目的 3、interrupt()和isInterrupted()配合使用,本質上和方法2一樣 重點看方法3
理解java執行緒的中斷(interrupt)
一個執行緒在未正常結束之前, 被強制終止是很危險的事情. 因為它可能帶來完全預料不到的嚴重後果比如會帶著自己所持有的鎖而永遠的休眠,遲遲不歸還鎖等。 所以你看到Thread.suspend, Thread.stop等方法都被Deprecated了 那麼不能直接
java執行緒學習(三):執行緒中斷 interrupt() 方法的使用
上一章節中,我們對執行緒終止stop方法進行了講解,stop終止執行緒的方法已經被丟棄,原因是執行緒的終止太暴力,會導致不必要的資料錯誤,所以stop方法在不自信的情況下,慎用慎用。。。。同時,也提供了較為完善的終止方案了。 本節就來學習執行緒中斷 interrupt() 方法的使用: 一、
Java執行緒中斷理解(interrupte)
Java執行緒之中,一個執行緒的生命週期分為:初始、就緒、執行、阻塞以及結束。當然,其中也可以有四種狀態,初始、就緒、執行以及結束。 一般而言,可能有三種原因引起阻塞:等待阻塞、同步阻塞以及其他阻塞(睡眠、jion或者IO阻塞);對於Ja
【雜談】執行緒中斷——Interrupt
前言 以前有一個錯誤的認識,以為中斷操作都會丟擲異常,後來才發現並不是這樣,所以今天就來做一個關於中斷的總結。 如何關閉執行緒 已被棄用的Stop方法 早期,Thread類中有一個stop方法,用於強行關閉一個執行緒。但是後來發現此操作並不安全,強行關閉可能導致一致性問題。故stop方
理解Java執行緒
使用多執行緒的目的是更好的利用cpu資源,大部分多執行緒程式碼都可以用單執行緒來實現,但也有無法用單執行緒實現的,如:生產者消費者模型 下面對一些常用的概念進行區分: 多執行緒:指的是這個程式(一個程序)執行時產生了不止一個執行緒。 並行與併發: 並行:多個cpu例項或者多臺機器同時執行一段處理邏輯,真正的同
一文搞懂 Java 執行緒中斷
在之前的一文《如何"優雅"地終止一個執行緒》中詳細說明了 stop 終止執行緒的壞處及如何優雅地終止執行緒,那麼還有別的可以終止執行緒的方法嗎?答案是肯定的,它就是我們今天要分享的——執行緒中斷。 下面的這斷程式碼大家應該再熟悉不過了,執行緒休眠需要捕獲或者丟擲
深入理解Java執行緒池(1):ThreadPoolExecutor整體流程梳理,建立worker相關方法
執行緒池作為一個執行緒的容器,主要的作用就是防止頻繁建立執行緒,節省時間資源和cpu資源。雖然一定程度上佔用了記憶體,但實際情況下利遠遠大於弊。 構造方法 public ThreadPoolExecutor( int corePoolSize, //核
執行緒中斷 interrupt()
interrupt()是什麼? interrupt是Thread例項為我們提供的方法,通過這個方法可以向執行緒發出中斷訊號 為什麼要中斷? 作為一個設計良好的執行緒類,在編寫每行程式碼時必須考慮特殊情況,其中一項就是中斷 中斷的原因執行緒本身並不清除,但
深入理解Java執行緒池原理分析與使用(尤其當執行緒佇列滿了之後事項)
在這裡借花獻佛了,那別人的東西學一學了。在我們的開發中“池”的概念並不罕見,有資料庫連線池、執行緒池、物件池、常量池等等。下面我們主要針對執行緒池來一步一步揭開執行緒池的面紗。使用執行緒池的好處1、降低資源消耗可以重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗。2、提高響應速度當任務到達時,任務可以不需
java執行緒中斷機制
利用標誌變數 通過檢查volatile型別的標誌變數控制執行緒中斷,不使用volatile型別的標誌變數會導致jvm對記憶體的優化引起死迴圈 public class StopThread { private static volatile bo
深入理解java執行緒池—ThreadPoolExecutor
幾句閒扯:首先,我想說java的執行緒池真的是很繞,以前一直都感覺新建幾個執行緒一直不退出到底是怎麼實現的,也就有了後來學習ThreadPoolExecutor原始碼。學習原始碼的過程中,最噁心的其實就是幾種狀態的轉換了,這也是ThreadPoolExecutor的核心。花了
棟哥帶你學Java執行緒中斷
執行緒中斷 (一)stop方法 在早期,執行緒中又一個stop方法,可以直接終止執行緒.但是現在已經不用了,而且api上也已經在方法下標明已過時.這時因為stop方法一旦呼叫,不管執行緒是什麼狀態的都直接會被終 止,假如正在執行執行緒,run方法中的程式
深入理解 Java 執行緒池
一、簡介 什麼是執行緒池 執行緒池是一種多執行緒處理形式,處理過程中將任務新增到佇列,然後在建立執行緒後自動啟動這些任務。 為什麼要用執行緒池 如果併發請求數量很多,但每個執行緒執行的時間很短,就會出現頻繁的建立和銷燬執行緒。如此一來,會大大降低系統的效率,可能頻繁建立和銷燬執行緒的時間、資源開銷要大於實際工
執行緒中斷 interrupt 和 LockSupport
本文章將要介紹的內容有以下幾點,讀者朋友也可先自行思考一下相關問題: 執行緒中斷 interrupt 方法怎麼理解,意思就是執行緒中斷了嗎?那當前執行緒還能繼續執行嗎? 判斷執行緒是否中斷的方法有幾個,它們之間有什麼區別? LockSupport的 park/unpark 和 wait/notify 有什麼
深入理解Java執行緒狀態轉移
目錄前言狀態轉移圖1.0 新建態到就緒態1.1 就緒態到執行態1.2 執行態到就緒態1.2.1 時間片用完1.2.2 t1.yield() 、Thread.yield();1.3 執行態到阻塞態1.3.1 Thread.sleep()1.3.2 t2.join()1.3.3 t1等待使用者輸入,等待鍵盤響應1
Java執行緒Thread之interrupt中斷解析
轉載請標明出處: http://blog.csdn.net/hesong1120/article/details/79164445 本文出自:hesong的專欄 這一篇我們說說Java執行緒Thread的interrupt中斷機制。 interrupt之中斷狀態
Java併發程式設計(2):執行緒中斷(含程式碼)
使用interrupt()中斷執行緒當一個執行緒執行時,另一個執行緒可以呼叫對應的Thread物件的interrupt()方法來中斷它,該方法只是在目標執行緒中設定一個標誌,表示它已經被中斷,並立即返回。這裡需要注意的是,如果只是單純的呼叫interrupt()方法,執行緒並沒有實際被中斷,會繼續往下執行。
Java 執行緒(Thread)技術與深入理解
Thread基礎部分 在各種程式語言中都有thread(執行緒)技術,執行緒保證在一個main中(主執行緒)可以同時進行兩個或多個不同的事件,通俗點說就是你在上廁所的同時還可以玩手機,是吧!美滋滋。而Thread就相當於提供了同時做兩件事的條件和環境。接下來在深入一點理解計算機中的Threa