日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java线程中断机制-如何中断线程

發(fā)布時(shí)間:2025/3/15 java 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java线程中断机制-如何中断线程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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)記,是否中斷是他自己的事

其中一次的輸出:

…… i=75722 end! should be stopped and exit this line is also executed. thread does not stopped


由于線程執(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();

? ? ?}

? }

}
輸出:

…… i=131892 should be stopped and exit end!


但是通過拋出異常也帶來(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。