上文講解了Java線程的創建、啟動以及停止,在講到停止線程時說到了Java中斷,Java中斷是停止線程的一種協作機制,本文打算對Java中斷機制進行詳細講解。
在網上搜索Java中斷機制,發現兩篇好文章,分別如下:Java 理論與實踐: 處理 InterruptedException 以及 詳細分析Java中斷機制,推薦大家仔細閱讀。
中斷是一種協作機制
必須記住,中斷是一種協作機制。當一個線程中斷另一個線程時,被中斷的線程不一定要立即停止正在做的事情。相反,中斷是禮貌地請求另一個線程在它願意並且方便的時候停止它正在做的事情。有些方法,例如 Thread.sleep(),很認真地對待這樣的請求,但並不是每個方法一定要對中斷作出響應。 您可以隨意忽略中斷請求,但是這樣做的話會影響響應。
中斷狀態
每個Java線程都有一個與之相關聯的 Boolean 屬性,該屬性用於表示線程的中斷狀態,Thread類提供了三個方法用於操作中斷狀態,這些方法包括:
public static boolean interrupted() |
測試當前線程是否已經中斷。線程的中斷狀態 由該方法清除。換句話說,如果連續兩次調用該方法,則第二次調用將返回 false(在第一次調用已清除了其中斷狀態之后,且第二次調用檢驗完中斷狀態前,當前線程再次中斷的情況除外)。 |
public booleanisInterrupted() | 測試線程是否已經中斷。線程的中斷狀態不受該方法的影響。 |
public voidinterrupt() | 中斷線程。 |
三個方法中,interrupt()方法是唯一能將中斷狀態設置為true的方法,另外兩個方法都是用於檢測當前中斷狀態的方法。
中斷的處理
作為一種協作機制,中斷機制不會強求被中斷線程一定要在某個點進行處理。實際上,被中斷線程只需在合適的時候處理中斷即可,如果沒有合適的時間點,甚至可以不處理,這時候在任務處理層面,就跟沒有調用中斷方法一樣。
在JDK中,有很多阻塞方法的聲明中有拋出InterruptedException異常,這暗示該方法是可中斷的,這些方法會檢測當前線程是否被中斷,如果是,則立刻結束阻塞方法,並拋出InterruptedException異常。如果程序捕獲到這些可中斷的阻塞方法拋出的InterruptedException或檢測到中斷后,這些中斷信息該如何處理?一般有以下兩個通用原則:
- 如果遇到的是可中斷的阻塞方法拋出InterruptedException,可以繼續向方法調用棧的上層拋出該異常,如果是檢測到中斷,則可清除中斷狀態並拋出InterruptedException,使當前方法也成為一個可中斷的方法。
- 若有時候不太方便在方法上拋出InterruptedException,比如要實現的某個接口中的方法簽名上沒有throws InterruptedException,這時就可以捕獲可中斷方法的InterruptedException並通過Thread.currentThread.interrupt()來重新設置中斷狀態。如果是檢測並清除了中斷狀態,亦是如此。
一般的代碼中,尤其是作為一個基礎類庫時,絕不應當吞掉中斷,即捕獲到InterruptedException后在catch里什么也不做,清除中斷狀態后又不重設中斷狀態也不拋出InterruptedException等。因為吞掉中斷狀態會導致方法調用棧的上層得不到這些信息。
當然,凡事總有例外的時候,當你完全清楚自己的方法會被誰調用,而調用者也不會因為中斷被吞掉了而遇到麻煩,就可以這么做。
不可取消的任務
有些任務拒絕被中斷,這使得它們是不可取消的。但是,即使是不可取消的任務也應該嘗試保留中斷狀態,以防在不可取消的任務結束之后,調用棧上更高層的代碼需要對中斷進行處理。以下代碼展示了一個方法,該方法等待一個阻塞隊列,直到隊列中出現一個可用項目,而不管它是否被中斷。為了方便他人,它在結束后在一個 finally 塊中恢復中斷狀態,以免剝奪中斷請求的調用者的權利。
public Task getNextTask(BlockingQueue<Task> queue) { boolean interrupted = false; try { while (true) { try { return queue.take(); } catch (InterruptedException e) { interrupted = true; // fall through and retry } } } finally { if (interrupted) Thread.currentThread().interrupt(); } }
總結
中斷是一種協作機制,利用該機制我們可以構造靈活的線程取消策略,每個線程都可以自行決定它們是可取消的還是不可取消的,以及如何對中斷作出響應,如果立即返回會危害應用程序完整性的話,它們還可以推遲中斷。
參考:
Java 理論與實踐: 處理 InterruptedException:http://www.ibm.com/developerworks/cn/java/j-jtp05236.html
詳細分析Java中斷機制:http://www.infoq.com/cn/articles/java-interrupt-mechanism