1. 程式人生 > >Thread.interrupt()方法理解(轉)

Thread.interrupt()方法理解(轉)

在java中,執行緒的中斷(interrupt)只是改變了執行緒的中斷狀態,至於這個中斷狀態改變後帶來的結果,那是無法確定的,有時它更是讓停止中的執行緒繼續執行的唯一手段。不但不是讓執行緒停止執行,反而是繼續執行執行緒的手段。

對於執行一般邏輯的執行緒,如果呼叫它的interrupt()方法,那麼對這個執行緒沒有任何 
影響,比如執行緒a正在執行: 
while(條件) x ++; 
這樣的語句,如果其它執行緒呼叫a.interrupt();那麼並不會影響a物件上執行的執行緒,但中斷標誌會變為true。如果在其它執行緒裡再次測試a的中斷狀態,則中斷標誌為true,但並不會停止這個執行緒的執行。

在一個執行緒物件上呼叫interrupt()方法,真正有影響的是wait,join,sleep方法,當然這三個方法包括它們的過載方法。

請注意:[上面這三個方法都會丟擲InterruptedException],記住這句話,下面我會重複。一個執行緒在呼叫interrupt()後,自己不會丟擲InterruptedException異常,所以你看到interrupt()並沒有丟擲這個異常,所以我上面說如果執行緒a正在執行while(條件) x ++;你呼叫a.interrupt()後執行緒會繼續正常地執行下去. 
附: 
Thread.sleep()原始碼:

public static native void sleep(long millis) throws InterruptedException;
  • 1

Object.wait()原始碼:

public final native void wait(long timeout) throws InterruptedException;
  • 1

Thread.join()原始碼

public final synchronized void join(long millis) throws InterruptedException {
    ...
}
  • 1
  • 2
  • 3

但是,如果一個執行緒被呼叫了interrupt()後,它的狀態是阻塞狀態的。而且這個狀態是由於正在執行wait,join,sleep的執行緒導致的,那麼是會改變執行緒的執行結果.

一. 對於wait中的等待notify、notifyAll換新的執行緒,其實這個執行緒已經“暫停”執行,因為它正在某一物件的休息室中,這時如果它的中斷狀態被改變,那麼它就會丟擲異常。這個InterruptedException異常不是執行緒丟擲的,而是wait方法,也就是物件的wait方法內部會不斷檢查在此物件上休息的執行緒的狀態,如果發現哪個執行緒的狀態被置為已中斷,則會丟擲InterruptedException,意思就是這個執行緒不能再等待了,其意義就等同於喚醒它了,然後執行catch中的程式碼。

這裡唯一的區別是,被nortify/All喚醒的執行緒會繼續執行wait下面的語句,而在wait 
中被中斷的執行緒則將控制權交給了catch語句。一些正常的邏輯要被放到catch中來執行。但有時這是唯一手段,比如一個執行緒a在某一物件b的wait中等待喚醒,其它執行緒必須獲取到物件b的監視鎖才能呼叫b.notify()[All],否則你就無法喚醒執行緒a,但在任何執行緒中可以無條件地呼叫a.interrupt();喚醒後的邏輯你要放在catch中,當然同notify/All一樣,繼續執行a執行緒的條件還是要等拿到b物件的監視鎖。

二. 對於sleep中的執行緒,如果你呼叫了Thread.sleep(一年);現在你後悔了,想讓它早 
些醒過來,呼叫interrupt()方法就是唯一手段,只有改變它的中斷狀態,讓它從sleep中將控制權轉到處理異常的catch語句中,然後再由catch中的處理轉換到正常的邏輯。同樣,對於join中的執行緒你也可以這樣處理。

對於一般介紹多執行緒模式的書上,他們會這樣來介紹:當一個執行緒被中斷後,在進入wait,sleep,join方法時會丟擲異常。是的,這一點也沒有錯,但是這有什麼意義呢?如果你知道那個執行緒的狀態已經處於中斷狀態,為什麼還要讓它進入這三個方法呢?當然有時是必須這麼做的,但大多數時候沒有這麼做的理由,所以我上面主要介紹了在已經呼叫這三個方法的執行緒上呼叫interrupt()方法讓它從這幾個方法的”暫停”狀態中恢復過來。這個恢復過來就可以包含兩個目的: 
一. [可以使執行緒繼續執行],那就是在catch語句中執行醒來後的邏輯,或由catch語句 
轉回正常的邏輯。總之它是從wait,sleep,join的暫停狀態活過來了。 
二. [可以直接停止執行緒的執行],當然在catch中什麼也不處理,或return,那麼就完成了當前執行緒的使命,可以使在上面”暫停”的狀態中立即真正的”停止”。