Java线程中断机制-如何中断线程
Java線程中斷機(jī)制-如何中斷線程
?版權(quán)聲明:本文為博主原創(chuàng)文章,歡迎指正或者轉(zhuǎn)載。 https://blog.csdn.net/qq_38663729/article/details/78232648
介紹:
對(duì)于線程一共分為五個(gè)狀態(tài):新建狀態(tài),就緒狀態(tài),阻塞狀態(tài),運(yùn)行狀態(tài),死亡狀態(tài),有時(shí)候把阻塞狀態(tài)又分為同步阻塞和等待阻塞。
有時(shí)想讓主線程啟動(dòng)的一個(gè)子線程結(jié)束運(yùn)行,我們就需要讓這個(gè)子線程中斷,不再繼續(xù)執(zhí)行。線程是有中斷機(jī)制的,我們可以對(duì)每個(gè)線程進(jìn)行中斷標(biāo)記,注意只是標(biāo)記,中斷與否還是虛擬機(jī)自己的事情,虛擬機(jī)自己家的事情,我們也就說(shuō)說(shuō),不能實(shí)際操作控制他家。java中的Thread類是一個(gè)對(duì)線程進(jìn)行操作的類,提供了中斷線程的方法interrupt(),在API中是這么定義的(中文的翻譯可能不準(zhǔn)確)。
在Thread中其實(shí)還有一個(gè)stop()方法也是中斷線程的方法,但是這個(gè)方法太粗魯了,人家好好的線程正在運(yùn)行,只要調(diào)用了stop()方法,線程就會(huì)中斷,不管是在進(jìn)行什么操作。這個(gè)方法已經(jīng)被廢棄,他的執(zhí)行會(huì)帶來(lái)一些不可確定的狀況。
線程可以調(diào)用中斷自己的方法interrupt()方法,但是中斷也是有條件的,在線程調(diào)用interrupt()方法的時(shí)候虛擬機(jī)會(huì)在此線程上標(biāo)記一個(gè)標(biāo)志(這個(gè)中斷標(biāo)志只是一個(gè)布爾類型的變量),代表這個(gè)線程可能被中斷,在后面的中斷操作也是根據(jù)這個(gè)中斷標(biāo)志執(zhí)行的。可以說(shuō)interrupt()方法是一種友好的方法,總是和虛擬機(jī)商量著來(lái)。如果一個(gè)線程處于了阻塞狀態(tài)(如線程調(diào)用了sleep()、join()、wait()、以及可中斷的通道上的 I/O 操作方法后可進(jìn)入阻塞狀態(tài)),則在線程在檢查中斷標(biāo)示時(shí)如果發(fā)現(xiàn)中斷標(biāo)示為true,則會(huì)在這些阻塞方法(sleep()、join()、wait()及可中斷的通道上的 I/O 操作方法)調(diào)用處拋出InterruptedException異常,并且在拋出異常后立即將線程的中斷標(biāo)示位清除,即重新設(shè)置為false。拋出異常是為了線程從阻塞狀態(tài)醒過來(lái),并在結(jié)束線程前讓程序員有足夠的時(shí)間來(lái)處理中斷請(qǐng)求。
線程的一些狀態(tài)都可能影響到這個(gè)中斷標(biāo)記從而結(jié)束中斷。下面這個(gè)例子驗(yàn)證中斷標(biāo)志被除掉的說(shuō)法
package demo_thread;
public class Interrupt {
?public static void main(String[] args) {
? ?A a = new A();
? ?Thread t1 = new Thread(a);
? ?t1.start();
? ?t1.interrupt();
? ?System.out.println("執(zhí)行睡眠之前1:"+t1.isInterrupted());
? ?try {
? ? ?System.out.println("執(zhí)行睡眠之前2:"+t1.isInterrupted());
? ? ?t1.sleep(1000);//線程進(jìn)入阻塞狀態(tài)
? ?} catch (InterruptedException e) {
? ? ?e.printStackTrace();
? ?}finally {
? ? System.out.println("執(zhí)行睡眠之后:"+t1.isInterrupted());
? ?}
?}
}
class A implements Runnable{
?@Override
?public void run() {
? ?System.out.println(Thread.currentThread());
?}
}
在main方法中創(chuàng)建一個(gè)線程,線程中重寫的run()方法輸出線程號(hào),只是一個(gè)顯示分隔,具體看在執(zhí)行讓線程阻塞方法之前和之后線程的中斷標(biāo)記。isInterrupted()方法是判斷線程是否執(zhí)行中斷的方法,就是判斷中斷標(biāo)記是否存在的方法。
輸出:
執(zhí)行睡眠之前1:true 執(zhí)行睡眠之前2:true Thread[Thread-0,5,main] 執(zhí)行睡眠之后:false可以看到只要執(zhí)行了sleep()方法,線程的中斷標(biāo)記就會(huì)被清除。分別調(diào)用執(zhí)行了join()、wait()方法,可以看到他們的共同點(diǎn)都是需要捕獲一個(gè)InterruptedException,在調(diào)用join()方法的時(shí)候得到了和sleep()方法一樣的輸出結(jié)果,但是在調(diào)用wait()方法的時(shí)候,雖然在后面調(diào)用notify()方法,但是是否獲得執(zhí)行權(quán)限還是無(wú)法預(yù)料的。
中斷一個(gè)線程只是為了引起該線程的注意,被中斷線程可以決定如何應(yīng)對(duì)中斷,中斷或者不中斷。某些線程非常重要,以至于它們應(yīng)該不理會(huì)中斷,而是在處理完拋出的異常之后繼續(xù)執(zhí)行,但是更普遍的情況是,一個(gè)線程將把中斷看作一個(gè)終止請(qǐng)求。
兩個(gè)很像的方法的區(qū)別:
interrupted():測(cè)試當(dāng)前線程是否中斷。 該方法可以清除線程的中斷狀態(tài) 。換句話說(shuō),如果這個(gè)方法被連續(xù)調(diào)用兩次,那么第二個(gè)調(diào)用將返回false(除非當(dāng)前線程再次中斷,在第一個(gè)調(diào)用已經(jīng)清除其中斷狀態(tài)之后,在第二個(gè)調(diào)用之前已經(jīng)檢查過)。
isInterrupted():測(cè)試這個(gè)線程是否被中斷。線程的中斷狀態(tài)不受此方法的影響。
如何中斷線程:
接下來(lái)看請(qǐng)求中斷之后發(fā)生的事情:在網(wǎng)上看到一個(gè)例子
package demo_thread;
?public class Interrupt {
? ?public static void main(String[] args) {
? ? ?try {
? ? ? MyThread thread = new MyThread();
? ? ? thread.start();
? ? ? Thread.sleep(2000);
? ? ? thread.interrupt();//請(qǐng)求中斷MyThread線程
? ? ?} catch (Exception e) {
? System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end!");
}
}
class MyThread extends Thread {
?@Override
?public void run() {
? ?super.run();
? ?for (int i = 0; i < 500000; i++) {
? ? ?if (this.interrupted()) {
? ? ? ?System.out.println("should be stopped and exit");
? ? ? ?break;
? ? ?}
? ? System.out.println("i=" + (i + 1));
? ?}
? //盡管線程被中斷,但并沒有結(jié)束運(yùn)行。這行代碼還是會(huì)被執(zhí)行
? System.out.println("this line is also executed. thread does not stopped");
? }
}
在文章的開頭處已經(jīng)說(shuō)了,線程執(zhí)行中斷方法,只是給線程一個(gè)中斷標(biāo)記,是否中斷是他自己的事
其中一次的輸出:
由于線程執(zhí)行了sleep()方法,進(jìn)入阻塞狀態(tài),所以在從阻塞狀態(tài)從新回到運(yùn)行狀態(tài)的時(shí)候,發(fā)現(xiàn)自己已經(jīng)有了中斷標(biāo)記,執(zhí)行if中的語(yǔ)句,線程的睡眠和執(zhí)行總是和計(jì)算機(jī)內(nèi)部有關(guān)系,所以每次輸出的結(jié)束數(shù)字總是不一樣的。
通過輸出結(jié)果我們發(fā)現(xiàn)一個(gè)很重要的問題,我們要的是線程的中斷,也就是關(guān)于線程的方法需要停止執(zhí)行,但是在循環(huán)外面的輸出語(yǔ)句也執(zhí)行了,這個(gè)中斷只是中斷了循環(huán)的執(zhí)行。
那么我們應(yīng)該怎么中斷線程呢?利用線程中斷異常就是一個(gè)很好的辦法,既然是異常,通常異常可以中斷線程的運(yùn)行,使程序掛掉,我們自己拋出一個(gè)異常讓線程中斷
class MyThread extends Thread {
? ? ? @Override
? ? ? public void run() {
? ? ? ?super.run();
? ? ? ?try {
? ? ? ? ?for (int i = 0; i < 500000; i++) {
? ? ? ? ? ?if (this.interrupted()) {
? ? ? ? ? ? ?System.out.println("should be stopped and exit");
? ? ? ? ? ? ?throw new InterruptedException();
? ? ? ? ? ? }
? ? ? ? ? System.out.println("i=" + (i + 1));
? ? ? ? ?}
? ? System.out.println("this line cannot be executed. cause thread throws exception");//這行語(yǔ)句不會(huì)被執(zhí)行!!!
? ? ? ?} catch (InterruptedException e) {
? ? ? ? ? System.out.println("catch interrupted exception");
? ? ? ? ? e.printStackTrace();
? ? ?}
? }
}
輸出:
但是通過拋出異常也帶來(lái)了問題,我們不能通過拋出異常來(lái)處理問題,還需要在捕獲異常的代碼中加上處理的語(yǔ)句,例如保存用戶的操作等等,讓這次中斷看起來(lái)是很正常的中斷。
我們還可以通過讓程序主動(dòng)拋出異常,在線程阻塞的時(shí)候,執(zhí)行中斷操作,拋出異常,在循環(huán)中循環(huán)打印當(dāng)前時(shí)間,
package demo_thread;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SleepInterruptTest {
?public static void main(String[] args) {
? ? SleepThread t1 = new SleepThread();
? ? t1.start();
? ? try {
? ? ? Thread.sleep(5000);
? ? } catch (InterruptedException e) {
? ? ? e.printStackTrace();
? ? }
? ?t1.interrupt();//主動(dòng)打斷線程,使SleepThread線程拋出異常
? }
}
class SleepThread extends Thread{
? ? public void run(){
? ? ? while(true){
? ? ? ?try{
? ? ? ? ?SimpleDateFormat sim = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
? ? ? ? ?System.out.println(sim.format(new Date()));
? ? ? ? ?sleep(1000);
? ? ? ? }
? ? ? ?catch(InterruptedException e){
? ? ? ?System.out.println("線程中斷");
? ? ? ?return;
? ? }
? ?}
? ?}
}
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Java线程中断机制-如何中断线程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hi3516A开发--ethtool安装
- 下一篇: java美元兑换,(Java实现) 美元