Java線程之中,一個線程的生命周期分為:初始、就緒、運行、阻塞以及結束。當然,其中也可以有四種狀態,初始、就緒、運行以及結束。
一般而言,可能有三種原因引起阻塞:等待阻塞、同步阻塞以及其他阻塞(睡眠、jion或者IO阻塞);對於Java而言,等待阻塞是調用wait方法產生的,同步阻塞則是由同步塊(synchronized)產生的,睡眠阻塞是由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(isIn) break;//退出循環,中斷進程
- }
- }catch (InterruptedException e){//阻塞狀態中進行中斷線程操作
- boolean isIn = this.isInterrupted();//退出阻塞狀態,且中斷標志被清除,重新設置為false,所以此處的isIn為false
- return;//退出run方法,中斷進程
- }
- }
分別考慮了阻塞狀態中進行中斷線程和非阻塞狀態中中斷線程的處理方式。
最后,說明一下interrupte方法的調用,該方法可在需要中斷的線程本身中調用,也可在其他線程中調用需要中斷的線程對象的該方法。