Java線程之中,一個線程的生命週期分爲:初始、就緒、運行、阻塞以及結束。當然,其中也可以有四種狀態,初始、就緒、運行以及結束。
一般而言,可能有三種原因引起阻塞:
- 等待阻塞>>等待阻塞是調用
wait
方法產生的 - 同步阻塞>>同步阻塞則是由同步塊(
synchronized
)產生的 - 以及其他阻塞(睡眠、
jion
或者IO阻塞)>>睡眠阻塞是由sleep產生的,jion
阻塞是由jion
方法產生的。
- 言歸正傳,要中斷一個Java線程,可調用線程類(Thread)對象的實例方法:interrupte();
- 然而interrupte()方法並不會立即執行中斷操作;
- 具體而言,這個方法只會給線程設置一個爲true的中斷標誌(中斷標誌只是一個布爾類型的變量),而設置之後,則根據線程當前的狀態進行不同的後續操作。
- 如果,線程的當前狀態處於非阻塞狀態,那麼僅僅是線程的中斷標誌被修改爲true而已;
- 如果線程的當前狀態處於阻塞狀態,那麼在將中斷標誌設置爲true後,還會有如下三種情況之一的操作:
- 如果是wait、sleep以及jion三個方法引起的阻塞,那麼會將線程的中斷標誌重新設置爲false,並拋出一個
InterruptedException
; - 如果是java.nio.channels.InterruptibleChannel進行的io操作引起的阻塞,則會對線程拋出一個ClosedByInterruptedException;(待驗證)
- 如果是輪詢(java.nio.channels.Selectors)引起的線程阻塞,則立即返回,不會拋出異常。(待驗證)
- 如果在中斷時,線程正處於非阻塞狀態,則將中斷標誌修改爲true,而在此基礎上,一旦進入阻塞狀態,則按照阻塞狀態的情況來進行處理;
例如,一個線程在運行狀態中,其中斷標誌被設置爲true,則此後,一旦線程調用了wait、jion、sleep方法中的一種,立馬拋出一個InterruptedException,且中斷標誌被清除,重新設置爲false。
通過上面的分析,我們可以總結,調用線程類的interrupted方法,其本質只是設置該線程的中斷標誌,將中斷標誌設置爲true,並根據線程狀態決定是否拋出異常。
因此,通過interrupted方法真正實現線程的中斷原理是:開發人員根據中斷標誌的具體值,來決定如何退出線程。
public void run() {
try {
while (true){
Thread.sleep(1000l);//阻塞狀態,線程被調用了interrupte()方法,清除中斷標誌,拋出InterruptedException
//dosomething
boolean isIn = this.isInterrupted();
//運行狀態,線程被調用了interrupte()方法,中斷標誌被設置爲true
//非阻塞狀態中進行中斷線程操作
if(isInterrupted()) break;//退出循環,中斷進程
}
}catch (InterruptedException e){//阻塞狀態中進行中斷線程操作
boolean isIn = this.isInterrupted();//退出阻塞狀態,且中斷標誌被清除,重新設置爲false,所以此處的isIn爲false
return;//退出run方法,中斷進程
}
}
分別考慮了阻塞狀態中進行中斷線程和非阻塞狀態中中斷線程的處理方式。
最後,說明一下interrupte方法的調用,該方法可在需要中斷的線程本身中調用,也可在其他線程中調用需要中斷的線程對象的該方法。