interrupt
原理
interrupt是Thread中的一個方法, 其本質是将線程中的中斷标志設定為true, 而不是直接中斷. 設定後, 根據線程的狀态而有不同的後續操作. 如果, 線程的目前狀态處于非阻塞狀态, 那麼僅僅是線程的中斷标志被改為了true, 一旦線程調用了wait, join, sleep方法中的一種, 立馬抛出InterruptedException, 并将中斷标志重置, 重新設定為false. 如果線程目前狀态處于阻塞狀态, 那麼會有三種情況之一:
- 如果是wait, join, sleep三個方法引起的阻塞, 那麼線程的中斷标志會重置為false, 并且抛出一個InterruptedException.
- 如果是java.nio.channels.InterruptibleChannel進行的IO阻塞, 會抛出ClosedByInterruptedException.
- 如果是java.nio.channels.Selectors引起的阻塞, 則立即傳回, 不會抛出異常.
循環體中catch
對InterruptedException的捕獲一般放在while循環體的外面, 這樣在産生異常的時候就退出了while循環, 否則InterruptedException在while之内, 就需要添加額外的退出處理.
@Override
public void run() {
while(true) {
try {
// todo
} catch(InterruptedException) {
// todo
break;
}
}
}
複制
isInterrupted()
@Override
public void run() {
while(!isInterrupted()) {
// todo
}
}
複制
isInterrupted()可以傳回中斷标志位的值, 表示運作中的線程是否被Thread.Interrupt()調用.
interrputed()
Interrupted()和isInterrupted()都可以傳回中斷标志位的值, 不同的是, 前者還會将中斷标志位重置為false.
中斷狀态與InterruptedException
調用Interrupt方法後, 可以中斷掉線程. 這裡的中斷是指:
- 線程變成”中斷狀态”.
- 線程catch到InterruptedException後的邏輯操作.
因為我們知道, 如果調用了interrput方法, 但是線程的狀态并不是在join, wait, sleep的話, 并不會抛出InterruptedException, 而是将interrupt标志位設為true, 這就是線程的”中斷狀态”.
中斷狀态 -> InterruptedException異常的轉換:
如果線程是中斷狀态, 那麼抛出InterruptedException異常:
if(Thread.interrupted()) {
throw new InterruptedException();
}
複制
這樣可以提高線程對于interrupt()的響應性. 注意Thread.interrupted()會抹掉标志位的值, 使其變成false. 如果不想對标志位改動, 可以調用Thread.currentThread().isInterrupted()方法.
InterruptedException異常 -> 中斷狀态的轉換:
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
Thread.currentThread().interrput();
}
複制
InterruptedException異常 -> InterruptedException異常:
InterruptedException savedInterruption = null;
try {
Thread.sleep(1000);
} catch (InterrputionException e) {
savedException = e;
}
if(savedException != null) {
throw savedException;
}
複制
延遲抛出異常.
注意
處于wait态中的線程在被interrupt後, 會跳出wait set, 并在下次獲得Object鎖的時候, 才會抛出InterruptedException.