原創聲明:作者:Arnold.zhao 博客園地址:https://www.cnblogs.com/zh94
一個線程不應該由其他線程來強制中斷或停止,而是應該由線程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.resume 都已經被廢棄了。Java Thread.interrupt()方法所提供的線程中斷,實際就是從線程外界,修改線程內部的一個標志變量,或者讓線程中的一些阻塞方法,拋出InterruptedException。以此”通知“線程去做一些事情, 至於做什么,做不做,實際完全是由線程內的業務代碼自己決定的。不過一般都是釋放資源並結束線程。
基本概念
public static void basic() {
Thread testThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println();
}
});
testThread.interrupt(); //是給線程設置中斷標志; 其作用是中斷此線程(此線程不一定是當前線程,而是指調用該方法的Thread實例所代表的線程)
testThread.isInterrupted(); //只檢測中斷; 作用於此線程,即代碼中調用此方法的實例所代表的線程;作用是只測試此線程是否被中斷 ,不清除中斷狀態。
testThread.interrupted(); //是檢測中斷並清除中斷狀態; 作用於當前線程(作用是測試當前線程是否被中斷(檢查中斷標志),返回一個boolean並清除中斷狀態,第二次再調用時中斷狀態已經被清除,將返回一個false)
Thread.interrupted(); //同上
//************************************
testThread.interrupt(); //設置指定testThread線程的狀態為中斷標志,
testThread.isInterrupted();// 檢測當前testThread線程是否被外界中斷;是則返回true
testThread.interrupted();//檢測當前testThread線程是否收到中斷信令,收到信令則返回true且清除中斷狀態,重新變更為false;
Thread.interrupted();//靜態方法,與testThread.interrupted()一樣,(檢測當前testThread線程是否被中斷,如果被中斷則返回true且清除中斷狀態,重新變更為未中斷狀態;) 作用於當前被執行線程,由於testThread內部線程在執行的時候,是無法獲取testThread引用的,所以如果想檢測當前自己的線程是否被中斷且清除中斷狀態,則可以使用Thread.interrupted()方法;
//如上,其實關於線程中斷一共也就上述三個方法,其中interrupt()和isInterrupted() 是線程實例方法,interrupted()則是線程的靜態方法;
//isInterrupted()是線程實例方法,所以,線程內部執行代碼中是無法獲取testThread的引用的所以無法執行實例方法isInterrupted();
//但其實,我們可以通過在線程內部執行代碼中使用 Thread.currentThread()獲取當前線程的實例,此時使用Thread.currentThread().isInterrupted() 的方式來調用isInterrupted()方法;等價於testThread.isInterrupted();
//等價與:線程外部做檢測用:testThread.isInterrupted(); 線程內部做檢測用:Thread.currentThread().isInterrupted()
}
線程中斷驗證
/**
* 驗證一般情況下使用interrupt() 中斷執行線程的例子
*/
public static void threadStopTest() {
Thread testThread = new Thread(new Runnable() {
@Override
public void run() {
//第一種情況:檢測線程是否收到中斷信令,收到則返回true,並清除當前的線程狀態,重新變更為未中斷;
/* while (!Thread.interrupted()) {
System.out.println("線程內代碼執行");
}
//此時再檢測當前該線程是否收到外界中斷信令,得到結果為false,因為使用Thread.interrupted(),在收到中斷信令后,會清除當前的線程狀態,所以此處進行判斷時則返回結果為false,線程狀態未收到中斷信令
System.out.println(Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread().isInterrupted());
*/
//第二種情況:檢測線程是否收到中斷信令,收到則返回true,只是檢測當前是否收到中斷信令,不清除當前的線程狀態,
while (!Thread.currentThread().isInterrupted()) {
System.out.println("線程內代碼執行");
}
//此時檢測當前該線程是否收到外界中斷信令,true表示收到,此處獲取結果為 true
System.out.println(Thread.currentThread().isInterrupted()); //true
System.out.println(Thread.currentThread().isInterrupted()); //true
//線程被中斷后執行該代碼塊,進行回收工作
System.out.println("線程收到外部中斷通知,已進行線程內部回收,中斷完成");
/*while (true) {
}*/
}
});
testThread.start();
try {
Thread.sleep(5000);
//等待5秒后 發出中斷信號,通知testThread線程進行中斷
testThread.interrupt();
//判斷當前該線程是否中斷完成
boolean flag = true;
int index = 0;
Thread.sleep(1000);
while (flag) {
//獲取指定線程是否收到中斷信號,返回true表示線程已經收到中斷信號,但線程正在運行,處理中;或者是已經收到了中斷信令,但是選擇了不中斷繼續執行;
// 如果返回false則存在兩種情況
//1、是當前該線程已經執行完畢,完成中斷;由於此時線程已經執行完成了,那么此處再獲取該線程的信令時則返回為false,
//2、該線程沒有完成中斷,但是該線程代碼內部使用了Thread.interrupted() 清除了線程的信令狀態,此時則也是返回結果為false,
System.out.println("檢測線程的中斷信號:" + testThread.isInterrupted());
//循環檢測10秒鍾,10秒后則跳出循環
Thread.sleep(1000);
index++;
if (index == 10) {
//停止檢測
flag = false;
}
}
if (!testThread.isInterrupted()) {
//TODO: testThread線程中斷完成,則執行該代碼塊
System.out.println("外部檢測testThread中斷完成");
} else {
//TODO: 否則,則執行另外代碼塊
System.out.println("外部檢測testThread中斷失敗");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
原創聲明:作者:Arnold.zhao 博客園地址:https://www.cnblogs.com/zh94
驗證線程中斷,拋出InterruptedException異常的情況
/**
* 驗證線程中斷,拋出InterruptedException異常的情況;
*/
public static void threadStopTest2() {
/**
* 當外部調用對應線程進行中斷的信令時,如果此時該執行線程處於被阻塞狀態,如;Thread.sleep(),Object.wait(),BlockingQueue#put、BlockingQueue#take 等
* 那么此時通過調用當前線程對象的interrupt方法觸發這些函數拋出InterruptedException異常。
* 當一個函數拋出InterruptedException異常時,表示這個方法阻塞的時間太久了,外部應用不想等它執行結束了。
* 當你的捕獲到一個InterruptedException異常后,亦可以處理它,或者向上拋出。
*
* 拋出時要注意???:當你捕獲到InterruptedException異常后,當前線程的中斷狀態已經被修改為false;
* 此時你若能夠處理中斷,正常結束線程,則不用理會該值;但如果你繼續向上拋InterruptedException異常,你需要再次調用interrupt方法,將當前線程的中斷狀態設為true。
*
*/
Thread testThread = new Thread(new Runnable() {
@Override
public void run() {
try {
//外部調用信令,要中斷該線程時,如果此時線程正在休眠或者阻塞中,則將會拋出異常
Thread.sleep(6000);
} catch (InterruptedException e) {
//第一種情況:進入異常捕獲,此處捕獲到異常,則說明當前該線程被外界要求進行中斷,此時我們可以選擇中斷該線程;那么此時后續的while循環則將不會被執行,線程執行完畢,則結束;
/*if (1 > 0) {
return;
}
*/
//第二種情況:當然,我們也可以選擇收到中斷信令后,不進行線程中斷;比如,當前的線程的確處於正常的阻塞期間,阻塞完成后,我還是要執行while循環的,等到最終while循環執行完畢后,才正常的結束線程的生命周期;
//那么此時,捕獲到異常后不做任何操作即可;需要注意的是,此時捕獲了InterruptedException異常后,此時的線程狀態將會自動被修改為false
// (false表示線程沒有收到過中斷信令,或者是線程已經中斷完成,或者是線程使用了Thread.interrupted()清除了信令狀態)沒有收到過中斷信令這個基本是不可能的,只要外部有進行調用,則百分百收到信令,除非是在調用中斷信令前,獲取了一下線程的狀態,此時則肯定是false的;如:先執行,testThread.isInterrupted(),再執行testThread.interrupt();則此時第一個執行的isInterrupted()肯定是false,這個場景意義不大;
//1、對於外界來說,收到線程的信令狀態是false,則表示該線程已經是執行完成了;當然存在線程信令為false是內部線程自己進行了轉換,但實際上並沒有停止線程執行的情況;
//所以一般情況下,按照約定來說,如果內部線程收到中斷請求后,此時如果需要繼續執行,不理會外部的中斷信令,那么此時可以執行:Thread.currentThread().interrupt();重新將內部狀態轉換為true
//這樣,外部線程在重新檢測當前線程的信令狀態時為true時,則知道,內部線程已經收到了中斷信令,而不是一直沒有收到中斷信令。
//此處為false,捕獲該中斷異常后,將會自動修改線程狀態為false,
System.out.println("異常" + Thread.currentThread().isInterrupted());
//此處由於要繼續執行該線程,不執行線程中斷,所以重新修改中斷狀態為true;
Thread.currentThread().interrupt();
//此時獲取結果為true;
System.out.println("異常" + Thread.currentThread().isInterrupted());
}
while (true) {
System.out.println("線程內部執行中");
}
}
});
testThread.start();
//發出線程中斷信令
testThread.interrupt();
}
約定
/**
* 約定:
* 內部中斷的線程,如果需要繼續執行,則必須重新設置信令狀態為true;此時外部調用者才會清楚當前線程已經收到中斷信令但是還要繼續執行;
* <p>
* 什么情況下,線程狀態會自動變更為false?
* <p>
* 1、線程自動執行完畢后,則狀態將會自動置為 false;
* 2、線程內部使用:Thread.interrupted()方法獲取線程狀態時,將會自動清除線程狀態,使當前線程狀態重新更改為false;
* 3、線程內部如果捕獲了,InterruptedException異常,那么此時線程狀態也會自動修改為false;
* <p>
* 所以,
* 1、如果是使用Thread.interrupted()來獲取線程狀態的情況,使用完以后,必須保證線程是正常中斷的;如果不能保證,建議使用Thread.currentThread().isInterrupted()來獲取線程狀態;isInterrupted()方法只獲取線程狀態,不會更改線程狀態;
* 2、對於線程內使用try catch 捕獲了InterruptedException異常的情況,則捕獲完以后,一定要做相關操作,而不要只捕獲異常,但是不處理該中斷信令;
* 當前捕獲到異常后,如果需要中斷,則直接中斷線程即可
* 當前捕獲到異常后,如果不需要中斷,需要繼續執行線程,則此時需要執行Thread.currentThread().interrupt();重新更改下自己的線程狀態為true,表示當前線程需要繼續執行;
* 當前捕獲到異常后,如果不需要中斷,而是將異常外拋給上層方法進行處理,那么此時也需要執行Thread.currentThread().interrupt();重新更改下自己的線程狀態為true,表示當前線程需要繼續執行;
*/
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
*/
}