一、線程中斷

1.什麼是線程中斷?

線程中斷是線程的標誌位屬性。而不是真正終止線程,和線程的狀態無關。線程中斷過程表示一個運行中的線程,通過其他線程調用了該線程的 interrupt() 方法,使得該線程中斷標誌位屬性改變。

深入思考下,線程中斷不是去中斷了線程,恰恰是用來通知該線程應該被中斷了。具體是一個標誌位屬性,到底該線程生命週期是去終止,還是繼續運行,由線程根據標誌位屬性自行處理。

2.線程中斷操作

調用線程的 interrupt() 方法,根據線程不同的狀態會有不同的結果。

下面新建 InterruptedThread 對象,代碼如下:

/**
* 一直運行的線程,中斷狀態為 true
*
* @author Jeff Lee @ bysocket.com
* @since 2019年04月17日15:03:02
*/
public class InterruptedThread implements Runnable {

@Override // 可以省略
public void run() {
// 一直 run
while (true) {
}
}

public static void main(String[] args) throws Exception {

Thread interruptedThread = new Thread(new InterruptedThread(), "InterruptedThread");
interruptedThread.start();

TimeUnit.SECONDS.sleep(2);

interruptedThread.interrupt();
System.out.println("InterruptedThread interrupted is " + interruptedThread.isInterrupted());

TimeUnit.SECONDS.sleep(2);
}
}

運行 main 函數,結果如下:

InterruptedThread interrupted is true

代碼詳解:

  • 線程一直在運行狀態,沒有停止或者阻塞等
  • 調用了 interrupt() 方法,中斷狀態置為 true,但不會影響線程的繼續運行

另一種情況,新建 InterruptedException 對象,代碼如下:

/**
* 拋出 InterruptedException 的線程,中斷狀態被重置為默認狀態 false
*
* @author Jeff Lee @ bysocket.com
* @since 2019年04月17日15:03:02
*/
public class InterruptedException implements Runnable {

@Override // 可以省略
public void run() {
// 一直 sleep
try {
TimeUnit.SECONDS.sleep(10);
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
}
}

public static void main(String[] args) throws Exception {

Thread interruptedThread = new Thread(new InterruptedException(), "InterruptedThread");
interruptedThread.start();

TimeUnit.SECONDS.sleep(2);

// 中斷被阻塞狀態(sleep、wait、join 等狀態)的線程,會拋出異常 InterruptedException
// 在拋出異常 InterruptedException 前,JVM 會先將中斷狀態重置為默認狀態 false
interruptedThread.interrupt();
System.out.println("InterruptedThread interrupted is " + interruptedThread.isInterrupted());
TimeUnit.SECONDS.sleep(2);
}
}

運行 main 函數,結果如下:

InterruptedThread interrupted is false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)

代碼詳解:

  • 中斷被阻塞狀態(sleep、wait、join 等狀態)的線程,會拋出異常 InterruptedException
  • 拋出異常 InterruptedException 前,JVM 會先將中斷狀態重置為默認狀態 false

小結下線程中斷:

  • 線程中斷,不是停止線程,只是一個線程的標誌位屬性
  • 如果線程狀態為被阻塞狀態(sleep、wait、join 等狀態),線程狀態退出被阻塞狀態,拋出異常 InterruptedException,並重置中斷狀態為默認狀態 false
  • 如果線程狀態為運行狀態,線程狀態不變,繼續運行,中斷狀態置為 true

代碼:https://github.com/JeffLi1993/java-concurrency-core-learning

二.線程終止

比如在 IDEA 中強制關閉程序,立即停止程序,不給程序釋放資源等操作,肯定是不正確的。線程終止也存在類似的問題,所以需要考慮如何終止線程?

上面聊到了線程中斷,可以利用線程中斷標誌位屬性來安全終止線程。同理也可以使用 boolean 變數來控制是否需要終止線程。

新建 ,代碼如下:

/**
* 安全終止線程
*
* @author Jeff Lee @ bysocket.com
* @since 2019年04月17日15:03:02
*/
public class ThreadSafeStop {

public static void main(String[] args) throws Exception {
Runner one = new Runner();
Thread countThread = new Thread(one, "CountThread");
countThread.start();
// 睡眠 1 秒,通知 CountThread 中斷,並終止線程
TimeUnit.SECONDS.sleep(1);
countThread.interrupt();

Runner two = new Runner();
countThread = new Thread(two,"CountThread");
countThread.start();
// 睡眠 1 秒,然後設置線程停止狀態,並終止線程
TimeUnit.SECONDS.sleep(1);
two.stopSafely();
}

private static class Runner implements Runnable {

private long i;

// 終止狀態
private volatile boolean on = true;

@Override
public void run() {
while (on && !Thread.currentThread().isInterrupted()) {
// 線程執行具體邏輯
i++;
}
System.out.println("Count i = " + i);
}

public void stopSafely() {
on = false;
}
}
}

從上面代碼可以看出,通過 while (on && !Thread.currentThread().isInterrupted()) 代碼來實現線程是否跳出執行邏輯,並終止。但是疑問點就來了,為啥需要 on 和 isInterrupted() 兩項一起呢?用其中一個方式不就行了嗎?答案在下面

線程成員變數 on 通過 volatile 關鍵字修飾,達到線程之間可見,從而實現線程的終止。但當線程狀態為被阻塞狀態(sleep、wait、join 等狀態)時,對成員變數操作也阻塞,進而無法執行安全終止線程

為了處理上面的問題,引入了 isInterrupted(); 只去解決阻塞狀態下的線程安全終止。

兩者結合是真的沒問題了嗎?不是的,如果是網路 io 阻塞,比如一個 websocket 一直再等待響應,那麼直接使用底層的 close 。

三、小結

很多好友介紹,如果用 Spring 棧開發到使用線程或者線程池,那麼盡量使用框架這塊提供的線程操作及框架提供的終止等


本文的重點是你有沒有收穫與成長,其餘的都不重要,希望讀者們能謹記這一點。同時我經過多年的收藏目前也算收集到了一套完整的學習資料,包括但不限於:分散式架構、高可擴展、高性能、高並發、Jvm性能調優、Spring,MyBatis,Nginx源碼分析,Redis,ActiveMQ、、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多個知識點高級進階乾貨,希望對想成為架構師的朋友有一定的參考和幫助。

需要更詳細思維導圖和以下資料的:後臺私信「資料」即可免費領取

喜歡這篇文章的可以點個贊,也可以關注我的專欄 java經驗分享 ,專欄頂部有免費獲取資料方式


推薦閱讀:
相關文章