Java中斷機制

引言

Java中斷機制為我們提供了一種"試圖"停止一個線程的方法。設想我們有一個線程阻塞在一個耗時的I/O中眨攘,我們又不想一直等下去主慰,那么我們怎么樣才能停止這個線程呢?答案就是Java的中斷機制鲫售。

從Java線程的狀態(tài)說起

Java線程的狀態(tài)包括:NEW共螺,RUNNABLE,BLOCKED情竹,WAITING藐不,TIMED_WAITING和TERMINATED總共六種狀態(tài):

    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

一個線程新建后,在調(diào)用該線程的start()方法之前秦效,該線程的狀態(tài)就是NEW雏蛮;當線程的start()方法被調(diào)用之后,該線程已經(jīng)準備被CPU調(diào)度阱州,此時線程的狀態(tài)就是RUNNABLE挑秉;如果一個對象的monitor lock被其他線程獲取了,這個時候我們再通過synchronized關鍵字去獲取改對象的monitor lock時苔货,線程就會進入BLOCKED狀態(tài)犀概;通過調(diào)用Thread#join()方法或者Object#wait()方法(不設置超時時間立哑,with no timeout)或者LockSupport#park()方法可以讓一個線程從RUNNABLE狀態(tài)轉(zhuǎn)為WAITING狀態(tài);TIMED_WAITING指線程處于等待中姻灶,但是這個等待是有期限的()铛绰,通過調(diào)用Thread#sleep(),Object#wait(long timeout)产喉,Thread#join(long timeout)至耻,LockSupport#parkNanos(),LockSupport#partUnitl()都可使線程切換到TIMED_WAITING狀態(tài)镊叁。最后一種狀態(tài)TERMINATED是指線程正常退出或者異常退出后的狀態(tài)尘颓。下面這張圖展示了這六種線程狀態(tài)之間的相互轉(zhuǎn)換關系:

線程狀態(tài)圖

當線程處于等待狀態(tài)或者有超時的等待狀態(tài)時(TIMED_WAITING,WAITING)我們可以通過調(diào)用線程的interrupt()方法來中斷線程的等待晦譬,此時線程會拋InterruptedException異常疤苹。例如Thread.sleep()方法:
public static native void sleep(long millis) throws InterruptedException;
此方法就會拋出這類異常。
但是當線程處于BLOCKED狀態(tài)或者RUNNABLE(RUNNING)狀態(tài)時敛腌,調(diào)用線程的interrupt()方法也只能將線程的狀態(tài)位設置為true卧土。停止線程的邏輯需要我們自己去實現(xiàn)。

中斷原理

查看java源碼可以看到Thread類中提供了跟中斷相關的一些方法:

    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();                                                 1

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {                                               2
                interrupt0();           // Just to set the interrupt flag  3
                b.interrupt(this);                                         4
                return;
            }
        }
        interrupt0();
    }

interrupt()方法用于中斷一個線程像樊,首先在第1處中斷方法會判斷當前caller線程是否具有中斷本線程的權限尤莺,如果沒有權限則拋出SecurityException異常。然后在2處方法會判斷阻塞當前線程的對象是否為空生棍,如果不為空颤霎,則在3處先設置線程的中斷flag為true,然后再由Interruptible對象(例如可以中斷的I/O操作)去中斷操作涂滴。從中我們也可以看到如果當前線程不處于WAITING或者TIMED_WAITING狀態(tài)友酱,則interrupt()方法也只是僅僅設置了該線程的中斷flag為true而已。

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

再看interrupted()方法柔纵,該方法是一個靜態(tài)的方法缔杉,最終會調(diào)用具體線程實例的isInterrupted()方法:

    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    
    private native boolean isInterrupted(boolean ClearInterrupted);

interrupted()方法第一次調(diào)用時會返回當前線程的中斷flag,然后就清除了這個狀態(tài)位搁料,但是isInterrupted()方法不會清除該狀態(tài)位或详。因此一個線程中斷后,第一次調(diào)用interrupted()方法會返回true郭计,第二次調(diào)用就返回false霸琴,因此第一次調(diào)用后該狀態(tài)位已經(jīng)被清除了。但是同樣一個線程中斷后拣宏,多次調(diào)用isInterrupted()方法都會返回true沈贝。這是兩者的不同之處杠人,但是兩者最終都會調(diào)用一個名為isInterrupted的native方法勋乾。

中斷的處理

java中一般方法申明了throws InterruptedException的就是可以中斷的方法宋下,比如:ReentrantLock#lockInterruptibly,BlockingQueue#put辑莫,Thread#sleep学歧,Object#wait等。當這些方法被中斷后會拋出InterruptedException異常各吨,我們可以捕獲這個異常枝笨,并實現(xiàn)自己的處理邏輯,也可以不處理揭蜒,繼續(xù)向上層拋出異常横浑。但是記住不要捕獲異常后什么都不做并且不向上層拋異常,也就是說我們不能"吞掉"異常屉更。
對于一些沒有拋出InterruptedException的方法的中斷邏輯只能由我們自己去實現(xiàn)了徙融。例如在一個大的循環(huán)中,我們可以自己判斷當前線程的中斷狀態(tài)然后選擇是否中斷當前操作:

public class InterruptTest {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 循環(huán)中檢測當前線程的中斷狀態(tài) 
                for (int i = 0; i < Integer.MAX_VALUE && !Thread.currentThread().isInterrupted(); i++) {
                    System.out.println(i);
                }
            }
        });
        thread.start();
        Thread.sleep(100);
        thread.interrupt();
    }
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瑰谜,一起剝皮案震驚了整個濱河市欺冀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌萨脑,老刑警劉巖隐轩,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異渤早,居然都是意外死亡职车,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門鹊杖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來提鸟,“玉大人,你說我怎么就攤上這事仅淑〕蒲” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵涯竟,是天一觀的道長赡鲜。 經(jīng)常有香客問我,道長庐船,這世上最難降的妖魔是什么银酬? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮筐钟,結(jié)果婚禮上揩瞪,老公的妹妹穿的比我還像新娘。我一直安慰自己篓冲,他們只是感情好李破,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布宠哄。 她就那樣靜靜地躺著,像睡著了一般嗤攻。 火紅的嫁衣襯著肌膚如雪毛嫉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天妇菱,我揣著相機與錄音承粤,去河邊找鬼。 笑死闯团,一個胖子當著我的面吹牛辛臊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播房交,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼浪讳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了涌萤?” 一聲冷哼從身側(cè)響起淹遵,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎负溪,沒想到半個月后透揣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡川抡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年辐真,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崖堤。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡侍咱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出密幔,到底是詐尸還是另有隱情楔脯,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布胯甩,位于F島的核電站昧廷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏偎箫。R本人自食惡果不足惜木柬,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淹办。 院中可真熱鬧眉枕,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至梗摇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間想许,已是汗流浹背伶授。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留流纹,地道東北人糜烹。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像漱凝,于是被迫代替她去往敵國和親疮蹦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Thread中斷機制涉及的方法或者屬性有三個: isInterrupted 首先看第一個茸炒,它很簡單愕乎,用來判斷這個線...
    懶眉閱讀 248評論 0 0
  • 一、并發(fā) 進程:每個進程都擁有自己的一套變量 線程:線程之間共享數(shù)據(jù) 1.線程 Java中為多線程任務提供了很多的...
    SeanMa閱讀 2,460評論 0 11
  • 一壁公、wait--notify--sleep Object obj = new Object(); obj.wait...
    fe0180bd6eaf閱讀 338評論 0 1
  • 0 前言 當線程被創(chuàng)建并啟動以后感论,它既不是一啟動就進入了執(zhí)行狀態(tài),也不是一直處于執(zhí)行狀態(tài)紊册。在線程的生命周期中比肄,它要...
    七寸知架構(gòu)閱讀 5,195評論 2 63
  • “小迷糊,你在看什么書呢囊陡?” “《進化論》芳绩。” “嗯撞反?你什么時候?qū)@方面感興趣了妥色?” “哎,我也不知道我是怎么來的...
    勇劍斬天罡_be7a閱讀 330評論 0 0