Java併發編程之線程篇之線程中斷(三)

前言

在上篇文章Java併發編程之線程篇之線程簡介(二)中咱們基本瞭解瞭如何建立一個線程並執行相應任務,可是並無提到如何中斷一個線程。例如:咱們有一個下載程序線程,該線程在沒有下載成功以前是不會退出的,假如這個時候用戶不想下載了,那咱們該如何中斷這個下載線程呢?下面咱們就來學習如何正確的中斷一個線程吧。java

對於過期的suspend()、resume()和stop()方法,這裏就不介紹了,有興趣的小夥伴能夠查閱相關資料。編程

Java線程的中斷機制

當咱們須要中斷某個線程時,看似咱們只須要調一箇中斷方法(調用以後線程就不執行了)就好了。可是Java中並無提供一個實際的方法來中斷某個線程(不考慮過期的stop()方法),只提供了一箇中斷標誌位,來表示線程在運行期間已經被其餘線程進行了中斷操做。也就是說線程只有經過自身來檢查這個標誌位,來判斷本身是否被中斷了。在Java中提供了三個方法來設置或判斷中斷標誌位,具體方法以下所示:markdown

//類方法,設置當前線程中標誌位
   public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // 設置中斷標誌位
                b.interrupt(this);
                return;
            }
        }
        interrupt0();//設置中斷標誌位
    }

    //靜態方法,判斷當前線程是否中斷,清除中斷標誌位
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

    //類方法,判斷當前線程是否中斷,不清除中斷標誌位
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
複製代碼

在上述方法中,咱們能夠經過interrupt()來設置相應線程中斷標誌,經過Thread類靜態方法interrupted()和類方法isInterrupted()來判斷對應線程是否被其餘線程中斷。併發

其中interrupted()與isInterrupted()方法的主要區別以下:ide

  • interrupted 判斷當前線程是否中斷(若是是中斷,則會清除中斷的狀態標誌,也就是若是中斷了線程,第一次調用這個方法返回true,第二次繼續調用則返回false。
  • isInterrupted 判斷線程是否已經中斷(不清除中斷的狀態標誌)。

使用interrupt()中斷線程

在上文中,咱們瞭解了線程的如何設置中斷標誌位與如何判斷標誌位,那如今咱們來使用interrupt()方法來中斷一個線程。先看下面這個例子。post

class InterruptDemo {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000000; i++) {
                    System.out.println("i=" + i);
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//輸出結果:
i=593210
i=593211
i=593212
i=593213
i=593214
i=593215
i=593216

複製代碼

運行上述代碼,觀察輸出結果,咱們發現線程並無被終止,緣由是由於interrupt()方法只會設置線程中斷標誌位,並不會真正的中斷線程。也就是說咱們只有本身來判斷線程是否終止。通常狀況下,當咱們檢查到線程被中斷(也就是線程標誌位爲true)時,會拋出一個InterruptedException異常,來中斷線程任務。具體代碼以下:學習

class InterruptDemo {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 1000000; i++) {
                        if (Thread.interrupted()) {
                            System.out.println("檢測到線程被中斷");
                            throw new InterruptedException();
                        }
                        System.out.println("i=" + i);
                    }
                } catch (InterruptedException e) {
                    //執行你本身的中斷邏輯
                    System.out.println("線程被中斷了,你本身判斷該如何處理吧");
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//輸出結果:
i=218626
i=218627
i=218628
i=218629
i=218630
檢測到線程被中斷
線程被中斷了,你本身判斷該如何處理吧
java.lang.InterruptedException
    at InterruptDemo$1.run(InterruptDemo.java:18)
    at java.base/java.lang.Thread.run(Thread.java:835)
複製代碼

在上述代碼中,咱們經過在線程中判斷Thread.interrupted()來判斷線程是否中斷,當線程被中斷後,咱們拋出InterruptedException異常。而後經過try/catch來捕獲該異常來執行咱們本身的中斷邏輯。固然咱們也能夠經過Thread.currentThread().isInterrupted()來判斷。這兩個方法的區別已經在上文介紹了,這裏就不過多的介紹了。this

中斷線程的另外一種方式

在上文中提到的使用interrupt()來中斷線程之外,咱們還能夠經過一個boolean來控制是否中斷線程。具體例子以下所示:spa

class InterruptDemo {

    public static void main(String[] args) {
        RunnableA runnableA = new RunnableA();
        Thread thread = new Thread(runnableA);
        thread.start();
        try {
            Thread.sleep(2000);
            runnableA.interruptThread();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class RunnableA implements Runnable {
        boolean isInterrupt;

        @Override
        public void run() {
            for (int i = 0; i < 1000000; i++) {
                if (!isInterrupt) {
                    System.out.println("i=" + i);
                } else {
                    System.out.println("線程結束運行了");
                    break;
                }
            }
        }

        void interruptThread() {
            isInterrupt = true;
        }
    }
}
//輸出結果:
i=240399
i=240400
i=240401
i=240402
i=240403
i=240404
i=240405
線程結束運行了
複製代碼

上述代碼中,咱們經過判斷isInterrupt的值來判斷是否跳出循環。run()方法的結束,就標誌着線程已經執行完畢了。線程

最後

站在巨人的肩膀上,才能看的更遠~

  • 《Java併發編程的藝術》
相關文章
相關標籤/搜索