Thread interrupt() 線程中斷的詳細說明
點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質(zhì)文章,第一時間送達
? 作者?|??Arnold-zhao
來源 |? urlify.cn/vuyaIv
一個線程不應(yīng)該由其他線程來強制中斷或停止,而是應(yīng)該由線程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.resume 都已經(jīng)被廢棄了。Java Thread.interrupt()方法所提供的線程中斷,實際就是從線程外界,修改線程內(nèi)部的一個標志變量,或者讓線程中的一些阻塞方法,拋出InterruptedException。以此”通知“線程去做一些事情, 至于做什么,做不做,實際完全是由線程內(nèi)的業(yè)務(wù)代碼自己決定的。不過一般都是釋放資源并結(jié)束線程。
基本概念
public?static?void?basic()?{
????????Thread?testThread?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????System.out.println();
????????????}
????????});
????????testThread.interrupt();?????????//是給線程設(shè)置中斷標志;??其作用是中斷此線程(此線程不一定是當前線程,而是指調(diào)用該方法的Thread實例所代表的線程)
??????? testThread.isInterrupted();?????//只檢測中斷;??作用于此線程,即代碼中調(diào)用此方法的實例所代表的線程;作用是只測試此線程是否被中斷?,不清除中斷狀態(tài)。
??????? testThread.interrupted();???????//是檢測中斷并清除中斷狀態(tài);?作用于當前線程(作用是測試當前線程是否被中斷(檢查中斷標志),返回一個boolean并清除中斷狀態(tài),第二次再調(diào)用時中斷狀態(tài)已經(jīng)被清除,將返回一個false)
????????Thread.interrupted();???????????//同上
????????//************************************
????????testThread.interrupt();?//設(shè)置指定testThread線程的狀態(tài)為中斷標志,
??????? testThread.isInterrupted();//?檢測當前testThread線程是否被外界中斷;是則返回true
????????testThread.interrupted();//檢測當前testThread線程是否收到中斷信令,收到信令則返回true且清除中斷狀態(tài),重新變更為false;
????????Thread.interrupted();//靜態(tài)方法,與testThread.interrupted()一樣,(檢測當前testThread線程是否被中斷,如果被中斷則返回true且清除中斷狀態(tài),重新變更為未中斷狀態(tài);)?作用于當前被執(zhí)行線程,由于testThread內(nèi)部線程在執(zhí)行的時候,是無法獲取testThread引用的,所以如果想檢測當前自己的線程是否被中斷且清除中斷狀態(tài),則可以使用Thread.interrupted()方法;
????????//如上,其實關(guān)于線程中斷一共也就上述三個方法,其中interrupt()和isInterrupted()?是線程實例方法,interrupted()則是線程的靜態(tài)方法;
????????//isInterrupted()是線程實例方法,所以,線程內(nèi)部執(zhí)行代碼中是無法獲取testThread的引用的所以無法執(zhí)行實例方法isInterrupted();
????????//但其實,我們可以通過在線程內(nèi)部執(zhí)行代碼中使用 Thread.currentThread()獲取當前線程的實例,此時使用Thread.currentThread().isInterrupted()?的方式來調(diào)用isInterrupted()方法;等價于testThread.isInterrupted();
????????//等價與:線程外部做檢測用:testThread.isInterrupted();?線程內(nèi)部做檢測用:Thread.currentThread().isInterrupted()
????}
線程中斷驗證
/**
?????*?驗證一般情況下使用interrupt()?中斷執(zhí)行線程的例子
?????*/
????public?static?void?threadStopTest()?{
????????Thread?testThread?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????//第一種情況:檢測線程是否收到中斷信令,收到則返回true,并清除當前的線程狀態(tài),重新變更為未中斷;
??????????????/*??while?(!Thread.interrupted())?{
????????????????????System.out.println("線程內(nèi)代碼執(zhí)行");
????????????????}
????????????????//此時再檢測當前該線程是否收到外界中斷信令,得到結(jié)果為false,因為使用Thread.interrupted(),在收到中斷信令后,會清除當前的線程狀態(tài),所以此處進行判斷時則返回結(jié)果為false,線程狀態(tài)未收到中斷信令
????????????????System.out.println(Thread.currentThread().isInterrupted());
????????????????System.out.println(Thread.currentThread().isInterrupted());
*/
????????????????//第二種情況:檢測線程是否收到中斷信令,收到則返回true,只是檢測當前是否收到中斷信令,不清除當前的線程狀態(tài),
????????????????while?(!Thread.currentThread().isInterrupted())?{
????????????????????System.out.println("線程內(nèi)代碼執(zhí)行");
????????????????}
????????????????//此時檢測當前該線程是否收到外界中斷信令,true表示收到,此處獲取結(jié)果為?true
????????????????System.out.println(Thread.currentThread().isInterrupted());?//true
????????????????System.out.println(Thread.currentThread().isInterrupted());?//true
????????????????//線程被中斷后執(zhí)行該代碼塊,進行回收工作
????????????????System.out.println("線程收到外部中斷通知,已進行線程內(nèi)部回收,中斷完成");
????????????????/*while?(true)?{
????????????????}*/
????????????}
????????});
????????testThread.start();
????????try?{
????????????Thread.sleep(5000);
????????????//等待5秒后?發(fā)出中斷信號,通知testThread線程進行中斷
????????????testThread.interrupt();
????????????//判斷當前該線程是否中斷完成
????????????boolean?flag?=?true;
????????????int?index?=?0;
????????????Thread.sleep(1000);
????????????while?(flag)?{
????????????????//獲取指定線程是否收到中斷信號,返回true表示線程已經(jīng)收到中斷信號,但線程正在運行,處理中;或者是已經(jīng)收到了中斷信令,但是選擇了不中斷繼續(xù)執(zhí)行;
????????????????//?如果返回false則存在兩種情況
????????????????//1、是當前該線程已經(jīng)執(zhí)行完畢,完成中斷;由于此時線程已經(jīng)執(zhí)行完成了,那么此處再獲取該線程的信令時則返回為false,
????????????????//2、該線程沒有完成中斷,但是該線程代碼內(nèi)部使用了Thread.interrupted()?清除了線程的信令狀態(tài),此時則也是返回結(jié)果為false,
????????????????System.out.println("檢測線程的中斷信號:"?+?testThread.isInterrupted());
????????????????//循環(huán)檢測10秒鐘,10秒后則跳出循環(huán)
????????????????Thread.sleep(1000);
????????????????index++;
????????????????if?(index?==?10)?{
????????????????????//停止檢測
????????????????????flag?=?false;
????????????????}
????????????}
????????????if?(!testThread.isInterrupted())?{
????????????????//TODO:?testThread線程中斷完成,則執(zhí)行該代碼塊
????????????????System.out.println("外部檢測testThread中斷完成");
????????????}?else?{
????????????????//TODO:?否則,則執(zhí)行另外代碼塊
????????????????System.out.println("外部檢測testThread中斷失敗");
????????????}
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????}
驗證線程中斷,拋出InterruptedException異常的情況
/**
?????*?驗證線程中斷,拋出InterruptedException異常的情況;
?????*/
????public?static?void?threadStopTest2()?{
????????/**
?????????*?當外部調(diào)用對應(yīng)線程進行中斷的信令時,如果此時該執(zhí)行線程處于被阻塞狀態(tài),如;Thread.sleep(),Object.wait(),BlockingQueue#put、BlockingQueue#take?等
?????????*?那么此時通過調(diào)用當前線程對象的interrupt方法觸發(fā)這些函數(shù)拋出InterruptedException異常。
?????????*?當一個函數(shù)拋出InterruptedException異常時,表示這個方法阻塞的時間太久了,外部應(yīng)用不想等它執(zhí)行結(jié)束了。
?????????*?當你的捕獲到一個InterruptedException異常后,亦可以處理它,或者向上拋出。
?????????*
?????????*?拋出時要注意???:當你捕獲到InterruptedException異常后,當前線程的中斷狀態(tài)已經(jīng)被修改為false;
?????????*?此時你若能夠處理中斷,正常結(jié)束線程,則不用理會該值;但如果你繼續(xù)向上拋InterruptedException異常,你需要再次調(diào)用interrupt方法,將當前線程的中斷狀態(tài)設(shè)為true。
?????????*
?????????*/
????????Thread?testThread?=?new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????try?{
????????????????????//外部調(diào)用信令,要中斷該線程時,如果此時線程正在休眠或者阻塞中,則將會拋出異常
????????????????????Thread.sleep(6000);
????????????????}?catch?(InterruptedException?e)?{
????????????????????//第一種情況:進入異常捕獲,此處捕獲到異常,則說明當前該線程被外界要求進行中斷,此時我們可以選擇中斷該線程;那么此時后續(xù)的while循環(huán)則將不會被執(zhí)行,線程執(zhí)行完畢,則結(jié)束;
????????????????????/*if?(1?>?0)?{
????????????????????????return;
????????????????????}
????????????????????*/
????????????????????//第二種情況:當然,我們也可以選擇收到中斷信令后,不進行線程中斷;比如,當前的線程的確處于正常的阻塞期間,阻塞完成后,我還是要執(zhí)行while循環(huán)的,等到最終while循環(huán)執(zhí)行完畢后,才正常的結(jié)束線程的生命周期;
????????????????????//那么此時,捕獲到異常后不做任何操作即可;需要注意的是,此時捕獲了InterruptedException異常后,此時的線程狀態(tài)將會自動被修改為false
????????????????????//?(false表示線程沒有收到過中斷信令,或者是線程已經(jīng)中斷完成,或者是線程使用了Thread.interrupted()清除了信令狀態(tài))沒有收到過中斷信令這個基本是不可能的,只要外部有進行調(diào)用,則百分百收到信令,除非是在調(diào)用中斷信令前,獲取了一下線程的狀態(tài),此時則肯定是false的;如:先執(zhí)行,testThread.isInterrupted(),再執(zhí)行testThread.interrupt();則此時第一個執(zhí)行的isInterrupted()肯定是false,這個場景意義不大;
????????????????????//1、對于外界來說,收到線程的信令狀態(tài)是false,則表示該線程已經(jīng)是執(zhí)行完成了;當然存在線程信令為false是內(nèi)部線程自己進行了轉(zhuǎn)換,但實際上并沒有停止線程執(zhí)行的情況;
????????????????????//所以一般情況下,按照約定來說,如果內(nèi)部線程收到中斷請求后,此時如果需要繼續(xù)執(zhí)行,不理會外部的中斷信令,那么此時可以執(zhí)行:Thread.currentThread().interrupt();重新將內(nèi)部狀態(tài)轉(zhuǎn)換為true
????????????????????//這樣,外部線程在重新檢測當前線程的信令狀態(tài)時為true時,則知道,內(nèi)部線程已經(jīng)收到了中斷信令,而不是一直沒有收到中斷信令。
????????????????????//此處為false,捕獲該中斷異常后,將會自動修改線程狀態(tài)為false,
????????????????????System.out.println("異常"?+?Thread.currentThread().isInterrupted());
????????????????????//此處由于要繼續(xù)執(zhí)行該線程,不執(zhí)行線程中斷,所以重新修改中斷狀態(tài)為true;
????????????????????Thread.currentThread().interrupt();
????????????????????//此時獲取結(jié)果為true;
????????????????????System.out.println("異常"?+?Thread.currentThread().isInterrupted());
????????????????}
????????????????while?(true)?{
????????????????????System.out.println("線程內(nèi)部執(zhí)行中");
????????????????}
????????????}
????????});
????????testThread.start();
????????//發(fā)出線程中斷信令
????????testThread.interrupt();
????}
約定
/**
?????*?約定:
?????*?內(nèi)部中斷的線程,如果需要繼續(xù)執(zhí)行,則必須重新設(shè)置信令狀態(tài)為true;此時外部調(diào)用者才會清楚當前線程已經(jīng)收到中斷信令但是還要繼續(xù)執(zhí)行;
?????*?
?????*?什么情況下,線程狀態(tài)會自動變更為false?
?????*?
?????*?1、線程自動執(zhí)行完畢后,則狀態(tài)將會自動置為?false;
?????* 2、線程內(nèi)部使用:Thread.interrupted()方法獲取線程狀態(tài)時,將會自動清除線程狀態(tài),使當前線程狀態(tài)重新更改為false;
?????*?3、線程內(nèi)部如果捕獲了,InterruptedException異常,那么此時線程狀態(tài)也會自動修改為false;
?????*?
?????*?所以,
?????* 1、如果是使用Thread.interrupted()來獲取線程狀態(tài)的情況,使用完以后,必須保證線程是正常中斷的;如果不能保證,建議使用Thread.currentThread().isInterrupted()來獲取線程狀態(tài);isInterrupted()方法只獲取線程狀態(tài),不會更改線程狀態(tài);
?????* 2、對于線程內(nèi)使用try catch 捕獲了InterruptedException異常的情況,則捕獲完以后,一定要做相關(guān)操作,而不要只捕獲異常,但是不處理該中斷信令;
?????*?當前捕獲到異常后,如果需要中斷,則直接中斷線程即可
?????*?當前捕獲到異常后,如果不需要中斷,需要繼續(xù)執(zhí)行線程,則此時需要執(zhí)行Thread.currentThread().interrupt();重新更改下自己的線程狀態(tài)為true,表示當前線程需要繼續(xù)執(zhí)行;
?????*?當前捕獲到異常后,如果不需要中斷,而是將異常外拋給上層方法進行處理,那么此時也需要執(zhí)行Thread.currentThread().interrupt();重新更改下自己的線程狀態(tài)為true,表示當前線程需要繼續(xù)執(zhí)行;
?????*/
public?static?void?main(String[]?args)?throws?InterruptedException?{
//????????threadStopTest();
????????/*
????????Thread.currentThread().interrupt();
????????System.out.println(Thread.currentThread().isInterrupted());true
????????System.out.println(Thread.currentThread().isInterrupted());true
????????System.out.println(Thread.currentThread().isInterrupted());true
????????System.out.println(Thread.interrupted());true
????????System.out.println(Thread.currentThread().isInterrupted());false
????????System.out.println(Thread.interrupted());false
????????*/
粉絲福利:Java從入門到入土學(xué)習(xí)路線圖
???

?長按上方微信二維碼?2 秒
感謝點贊支持下哈?
