interrupt、interruped、isinterruped的理解與使用、中斷線程的四種方法

這三個線程的方法,我理解了很久,很是容易搞混,這裏有個圖大家可以先看一下。

我首先碰到線程中斷是因爲一個面試題,中斷線程的方法,你能說出幾種?怎麼優雅的中斷線程?下面是我的理解

  1. 使用退出標誌,使線程正常退出,也就是當 run 方法完成 後線程終止。(優雅)
    public class ServerThread extends Thread {
        //volatile修飾符用來保證其它線程讀取的總是該變量的最新的值
        public volatile boolean exit = false; 
    
        @Override
        public void run() {
            ServerSocket serverSocket = new ServerSocket(8080);
            while(!exit){
                serverSocket.accept(); //阻塞等待客戶端消息
                ...
            }
        }
        
        public static void main(String[] args) {
            ServerThread t = new ServerThread();
            t.start();
            ...
            t.exit = true; //修改標誌位,退出線程
        }
    }
  2. 通過return 退出 run 方法
    /**
     * Created by edison on 2017/12/3.
     */
    public class MyThread12 extends Thread{
        @Override
        public void run() {
            super.run();
                for (int i = 0; i < 50000; i++) {
                    if (Thread.interrupted()) {
                        System.out.println("子線程已經停止了,我要退出");
                        return;
                    }
                    System.out.println("i="+(i+1));
                }
                System.out.println("for循環後繼續執行");
    
        }
    }
  3. 通過stop終止線程,就象突然關 閉計算機電源,而不是按正常程序關機一樣,可能會產生不可預料的結果用 stop() 方法會立刻停止 run() 方法中剩餘的全部工作,包括在 catch 或 finally 語句中的,並拋出ThreadDeath異常(通常情況下此異常不需要顯示的捕獲),因此可能會導致一些清理性的工作的得不到完成,如文件,數據庫等的關閉。已經被棄用
  4. Interrupt 方法結束線程。Thread.interrupt()方法: 作用是中斷線程。將會設置該線程的中斷狀態位,即設置爲true,中斷的結果線程是死亡、還是等待新的任務或是繼續運行至下一步,就取決於這個程序本身。線程會不時地檢測這個中斷標示位,以判斷線程是否應該被中斷(中斷標示值是否爲true)。它並不像stop方法那樣會中斷一個正在運行的線程。interrupt()方法只是改變中斷狀態,不會中斷一個正在運行的線程。
    public class InterruptionInJava implements Runnable{
     
        public static void main(String[] args) throws InterruptedException {
            Thread testThread = new Thread(new InterruptionInJava(),"InterruptionInJava");
            //start thread
            testThread.start();
            Thread.sleep(1000);
            //interrupt thread
            testThread.interrupt();
     
            System.out.println("main end");
     
        }
     
        @Override
        public void run() {
            while(true){
                if(Thread.currentThread().isInterrupted()){
                    System.out.println("Yes,I am interruted,but I am still running");
     
                }else{
                    System.out.println("not yet interrupted");
                }
            }
        }
    }

結果顯示,被中斷後,仍舊運行,不停打印Yes,I am interruted,but I am still running

 在理解interrupt和interruped、isinterruped時,我覺得遇到了一定的麻煩,我不明白,爲什麼interrupt方法作用是中斷線程,但是不會中斷一個正在運行的線程是什麼意思?這不是自相矛盾嗎?

  通過之後的查閱資料,我明白了,其實也很簡單,在調用interrupt方法時,線程有且僅有兩種狀態,

第一種:線程是running狀態。

當線程處於第一種狀態時,將線程的中斷標記爲true,就是說,線程可以被中斷啦,是否中斷是他自己的事。

在這裏,我又有疑問了,調用interrupt方法不是要結束線程嗎?爲什麼只標記可以被中斷,爲什麼不中斷,怎麼中斷?

當然可以通過return,但是要做的更通用,可以使用中斷標記,其實這兩種不需要調用interrupt方法就可以中斷線程。利用線程中斷異常就是一個很好的辦法,既然是異常,通常異常可以中斷線程的運行,使程序掛掉,我們自己拋出一個異常讓線程中斷。也可以使用sleep或wait阻塞方法,讓程序出現阻塞,拋出InterruptException異常。

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 cn.itcast.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());
            Thread.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());
    }
}

第二種:線程是阻塞狀態(使用了sleep、wait等方法時)。

當線程處於阻塞狀態時,調用線程的 interrupt()方法時,會拋出 InterruptException 異常。 阻塞中的那個方法拋出這個異常,通過代碼捕獲該異常,然後 break 跳出循環狀態,從而讓 我們有機會結束這個線程的執行。


而interruped、isinterruped方法的目的只是判斷線程是否中斷,沒有中斷線程的作用。只是interruped方法在檢測到線程中斷狀態爲true之後,返回true,之後又把中斷狀態清除了,恢復到了默認的false狀態,所以第二次調用的時候就是false狀態了。

class ATask implements Runnable{  
  
    private double d = 0.0;  
      
    public void run() {  
          
        //檢查程序是否發生中斷  
        while (!Thread.interrupted()) {  
            System.out.println("I am running!");  
  
            for (int i = 0; i < 900000; i++) {  
                d = d + (Math.PI + Math.E) / d;  
            }  
        }  
  
        System.out.println("ATask.run() interrupted!");  
    }  
}  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章