如何中斷線程?
已經拋棄的方法
- 通過調用stop()方法停止線程,該方法有點暴力停止的意思,比如線程A去停止線程B,停止的時候根本不知道線程B的執行情況,還有就是執行stop()之後,線程B會馬上釋放鎖,可能會引發數據不同步的問題
- 類似的被拋棄的還有suspend()和resume()方法
目前用的方法
- 調用interrupt(),通知線程應該中斷了
- 如果線程處於被阻塞狀態,那麼線程將立即退出被阻塞狀態,並拋出一個InterruptedException異常
- 如果線程處於正常活動狀態,那麼會將該線程的中斷標誌設置爲true。被設置中斷標誌的線程將繼續正常運行,不受影響
- 需要被調用的線程配合中斷
- 在正常運行任務時,可以自行檢查本線程的中斷標誌位(
Thread.currentThread().interrupt();
),如果被設置了中斷標誌可以由我們自行停止線程。
- 在正常運行任務時,可以自行檢查本線程的中斷標誌位(
測試
public static void main(String[] args) throws InterruptedException {
Runnable interruptTask = new Runnable() {
@Override
public void run() {
int i = 0;
try {
//在正常運行任務時,經常檢查本線程的中斷標誌位,如果被設置了中斷標誌就自行停止線程
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(100); // 休眠100ms
i++;
System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") 循環次數: " + i);
}
} catch (InterruptedException e) {
//在調用阻塞方法時正確處理InterruptedException異常。(例如,catch異常後就結束線程。)
System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") 捕獲中斷異常.");
}
}
};
Thread t1 = new Thread(interruptTask, "t1");
System.out.println(t1.getName() +" ("+t1.getState()+") 新建......");
t1.start(); // 啓動“線程t1”
System.out.println(t1.getName() +" ("+t1.getState()+") 已啓動......");
// 主線程休眠300ms,然後主線程給t1發“中斷”指令。
Thread.sleep(300);
t1.interrupt();
System.out.println(t1.getName() +" ("+t1.getState()+") 被中斷中......");
// 主線程休眠300ms,然後查看t1的狀態。
Thread.sleep(300);
System.out.println(t1.getName() +" ("+t1.getState()+") 線程終止......");
}
// 測試結果
t1 (NEW) 新建......
t1 (RUNNABLE) 已啓動......
t1 (RUNNABLE) 循環次數: 1
t1 (RUNNABLE) 循環次數: 2
t1 (TIMED_WAITING) 被中斷中......
t1 (RUNNABLE) 捕獲中斷異常.
t1 (TERMINATED) 線程終止......
- 這個測試便是一個簡單的中斷操作,將線程的中斷標識改爲true,我們在線程中設置了循環檢測器,一旦中斷標識被修改,則由我們自行進行停止。
- 這裏解釋一下爲什麼會拋出異常,因爲主線程中斷300ms後去中斷線程,線程中的while極大可能在執行第四次循環,位於sleep阻塞,故要拋出異常,然後結束線程。還有一點可以說明,結果倒數第三行,線程狀態爲
(TIMED_WAITING)
是限期等待,說明此時線程在執行sleep方法。
線程的六個狀態
上邊的測試裏面我們用到了getState()來獲取線程的狀態,下邊介紹一下線程的狀態:
-
新建(New):創建後未啓動的線程的狀態
-
運行(Runnable):包含Running和Ready,在操作系統中,它有可能正在執行也有可能正在等待cpu爲它分配執行時間
-
無限期等待(Waiting):不會被分配CPU執行時間,需要顯示地被喚醒
- 沒有設置Timeout參數的Object.wait()方法。
- 沒有設置Timeout參數的Thread.join()方法。
- LockSupport.park()方法
-
限期等待(Timed Waiting):在一定時間後會由系統自動喚醒
- Thread.sleep()
- 設置Timeout參數的Object.wait()方法。
- 設置Timeout參數的Thread.join()方法。
-
阻塞(Blocked):等待獲取排他鎖
-
結束(Terminated):已終止線程的狀態,線程已結束執行。終止的線程無法再次復生。
附上一張線程狀態圖
以上純爲個人理解,如有不對,請各位看官及時指出(輕噴)