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