天天看點

高并發程式設計-Thread#interrupt用法及源碼分析

文章目錄

  • ​​官網​​
  • ​​方法&源碼​​
  • ​​void interrupt()​​
  • ​​` boolean isInterrupted()` vs `static boolean interrupted()`​​
  • ​​方法&示例​​
  • ​​void interrupt()​​
  • ​​sleep()方法中測試interrupt​​
  • ​​wait()方法中測試interrupt​​
  • ​​join方法中測試interrupt​​
  • ​​boolean isInterrupted() 和 static boolean interrupted()​​
高并發程式設計-Thread#interrupt用法及源碼分析
高并發程式設計-Thread#interrupt用法及源碼分析

官網

我們看下Java8中Thread類關于interrupt的幾個方法

高并發程式設計-Thread#interrupt用法及源碼分析

先來看下基本用法,我們後面的例子再該示例上拓展

package com.artisan.test;

public class ThreadInterruptedDemo {

    public static void main(String[] args) {
        // 定義一個線程  死循環 調用start後一直運作
        Thread t = new Thread(() -> {
            while (true) {
            }
        }, "t");
        // 啟動線程
        t.start();

        // 檢視t的狀态
        System.out.println("before interrupt status>>>" + t.isInterrupted());
        // interrupt
        t.interrupt();
        // 檢視t的狀态
        System.out.println("after interrupt status>>>" + t.isInterrupted());

    }
}      

運作

高并發程式設計-Thread#interrupt用法及源碼分析

方法&源碼

檢視官方的API,可以看到 關于interrupt的 我們可以調用的API 主要有3個

void  interrupt()
  ----Interrupts this thread.
static boolean  interrupted()
  ---Tests whether the current thread has been interrupted.
boolean isInterrupted()
  ----Tests whether this thread has been interrupted      

void interrupt()

高并發程式設計-Thread#interrupt用法及源碼分析

大緻意思是說:

除非目前線程正在中斷自身(始終允許),否則将調用此線程的checkAccess方法,這可能導緻抛出SecurityException。

如果在調用Object類的wait(),wait(long)或wait(long,int)方法,或者join(),join(long),join(long,int)方法中阻塞了這個線程,sleep(long)或sleep(long,int),這個類的方法,然後它的中斷狀态将被清除,它将收到InterruptedException。

如果在InterruptibleChannel上的I / O操作中阻塞了該線程,則該通道将被關閉,線程的中斷狀态将被設定,并且線程将收到ClosedByInterruptException。

如果此線程在Selector中被阻塞,則線程的中斷狀态将被設定,并且它将立即從選擇操作傳回,可能具有非零值,就像調用選擇器的喚醒方法一樣。

如果以前的條件都不成立,則将設定該線程的中斷狀态。

中斷不活動的線程不會産生任何影響

我們來看下源碼,我這裡标注了下注釋

public void interrupt() {
 
        // 如果不是目前線程,抛出SecurityException異常
        if (this != Thread.currentThread())
            checkAccess();
        // 對blockerLock對象加鎖  private final Object blockerLock = new Object(); 
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // 調用interrupt0 這個native的方法 :Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }      

​boolean isInterrupted()​

​​ vs​

​static boolean interrupted()​

寫個例子 ,都在注釋裡了。

高并發程式設計-Thread#interrupt用法及源碼分析

方法&示例

void interrupt()

sleep()方法中測試interrupt

package com.artisan.test;

public class ThreadInterruptedDemo {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) { // 捕獲InterruptedException
                    System.out.println(Thread.currentThread().getName() + " 接收到打斷信号 ");
                    e.printStackTrace();
                }
            }
        }, "t");
        t.start();

        System.out.println("before interrupt status>>>" + t.isInterrupted());
        // interrupt
        t.interrupt();
        System.out.println("after interrupt status>>>" + t.isInterrupted());

    }
}      
高并發程式設計-Thread#interrupt用法及源碼分析

雖然捕獲了InterruptedException,但是該程式依舊還是運作,并沒有退出

wait()方法中測試interrupt

package com.artisan.test;

public class ThreadInterruptedDemo {

    private static  final Object MONITOR = new Object();


    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (true) {
                // 使用wait的時候,必須要使用synchronized 加鎖
                synchronized (MONITOR){
                    try {
                        MONITOR.wait(100);
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName() + " 接收到打斷信号 ");
                        e.printStackTrace();
                    }
                }
            }
        }, "t");
        t.start();

        System.out.println("before interrupt status>>>" + t.isInterrupted());
        // interrupt
        t.interrupt();
        System.out.println("after interrupt status>>>" + t.isInterrupted());

    }
}      

使用wait的時候,必須要使用synchronized 加鎖,這裡對一個Object對象加鎖

雖然捕獲了InterruptedException,但是該程式依舊還是運作,并沒有退出

高并發程式設計-Thread#interrupt用法及源碼分析

join方法中測試interrupt

這個比較有意思,我們來逐漸的測試下

先搭個基本的架子

package com.artisan.test;

public class ThreadInterruptedDemo {

    public static void main(String[] args)  {
        Thread t = new Thread(() -> {
            while (true) {

            }
        }, "t");

        // 啟動
        t.start();

        // join
        try {
            t.join();
        } catch (InterruptedException e) {
            System.out.println("收到中斷信号...");
            e.printStackTrace();
        }

        System.out.println("這裡永遠都不會執行到,因為t是個死循環... ");

    }
}      

因為一旦 join方法執行了以後,後面的代碼都會被阻塞住,是以必須要在join之前開辟另外一個線程

為了直覺,我們直接貼圖吧

高并發程式設計-Thread#interrupt用法及源碼分析

運作結果:

高并發程式設計-Thread#interrupt用法及源碼分析

**并沒有出現我們期望的InterruptedException **,w t f…

我們來分析下,上面的兩個例子 。

sleep 我們sleep的是 t 線程,我們調用了​

​t.interrupt​

​,收到了​

​InterruptedException​

wait 我們wait的也是t 線程,我們調用了​

​t.interrupt​

​,收到了​

​InterruptedException​

但是我們join的時候,​

​t.join​

​ ,這個時候join的不是線程t,是join的main線程 ,是以必須用main線程來調用interrupt , 改造下

高并發程式設計-Thread#interrupt用法及源碼分析

運作日志

boolean isInterrupted() 和 static boolean interrupted()