1. 程式人生 > >JAVA多執行緒之中斷機制(如何處理中斷?)

JAVA多執行緒之中斷機制(如何處理中斷?)

一,介紹

這篇文章主要記錄使用 interrupt() 方法中斷執行緒,以及如何對InterruptedException進行處理。感覺對InterruptedException異常進行處理是一件謹慎且有技巧的活兒。

由於使用stop()方法停止執行緒非常的暴力,人家執行緒執行的好好的,突然就把人家殺死了,執行緒佔用的鎖被強制釋放,極易導致資料的不一致性。可參考這篇文章對stop()方法的介紹。

因此,提出了一種溫和的方式:請求另外一個執行緒不要再執行了,這就是中斷方式。

二,中斷及如何響應中斷?

如何優雅地響應中斷真的是太高深了,看到這篇文章:Java 理論與實踐: 處理 InterruptedException

就嚇了一跳。下面只是記錄一些最簡單的我對響應中斷的理解。

假設某個執行緒要不停地處理某件事情(比如 i 一直自增),但是還有個要求:在處理事情前,先要檢查下這個執行緒是否被中斷,如果已經被中斷,處理就應該結束。

下面是一些例子,這些例子摘自書本:

 1 public class Run {
 2 
 3     public static void main(String[] args) {
 4         try {
 5             MyThread thread = new MyThread();
 6             thread.start();
7 Thread.sleep(20);//modify 2000 to 20 8 thread.interrupt();//請求中斷MyThread執行緒 9 } catch (InterruptedException e) { 10 System.out.println("main catch"); 11 e.printStackTrace(); 12 } 13 System.out.println("end!"); 14 } 15 }

main執行緒睡眠20ms後,執行第8行中斷MyThread執行緒。

 1 public class MyThread extends Thread {
 2     @Override
 3     public void run() {
 4         super.run();
 5         for (int i = 0; i < 500000; i++) {
 6             if (this.interrupted()) {
 7                 System.out.println("should be stopped and exit");
 8                 break;
 9             }
10             System.out.println("i=" + (i + 1));
11         }
12         System.out.println("this line is also executed. thread does not stopped");//儘管執行緒被中斷,但並沒有結束執行。這行程式碼還是會被執行
13     }
14 }

當MyThread獲得CPU執行時,第6行的 if 測試中,檢測到中斷標識被設定。即MyThread執行緒檢測到了main執行緒想要中斷它的 請求。

大多數情況下,MyThread檢測到了中斷請求,對該中斷的響應是:退出執行(或者說是結束執行)。

但是,上面第5至8行for迴圈,是執行break語句跳出for迴圈。但是,執行緒並沒有結束,它只是跳出了for迴圈而已,它還會繼續執行第12行的程式碼....

因此,我們的問題是,當收到了中斷請求後,如何結束該執行緒呢?

一種可行的方法是使用 return 語句 而不是 break語句。。。。。哈哈。。。

當然,一種更優雅的方式則是:丟擲InterruptedException異常。

看下面MyThread類的程式碼:

 1 public class MyThread extends Thread {
 2     @Override
 3     public void run() {
 4         super.run();
 5         try{
 6             for (int i = 0; i < 500000; i++) {
 7                 if (this.interrupted()) {
 8                     System.out.println("should be stopped and exit");
 9                     throw new InterruptedException();
10                 }
11                 System.out.println("i=" + (i + 1));
12             }
13             System.out.println("this line cannot be executed. cause thread throws exception");//這行語句不會被執行!!!
14         }catch(InterruptedException e){
15             System.out.println("catch interrupted exception");
16             e.printStackTrace();
17         }
18     }
19 }

當MyThread執行緒檢測到中斷標識為true後,在第9行丟擲InterruptedException異常。這樣,該執行緒就不能再執行其他的正常語句了(如,第13行語句不會執行)。這裡表明:interrupt()方法有兩個作用,一個是將執行緒的中斷狀態置位(中斷狀態由false變成true);另一個則是:讓被中斷的執行緒丟擲InterruptedException異常。

這是很重要的。這樣,對於那些阻塞方法(比如 wait() 和 sleep())而言,當另一個執行緒呼叫interrupt()中斷該執行緒時,該執行緒會從阻塞狀態退出並且丟擲中斷異常。這樣,我們就可以捕捉到中斷異常,並根據實際情況對該執行緒從阻塞方法中異常退出而進行一些處理。

比如說:執行緒A獲得了鎖進入了同步程式碼塊中,但由於條件不足呼叫 wait() 方法阻塞了。這個時候,執行緒B執行 threadA.interrupt()請求中斷執行緒A,此時執行緒A就會丟擲InterruptedException,我們就可以在catch中捕獲到這個異常並進行相應處理(比如進一步往上丟擲)

因此,上面就是一個採用丟擲異常的方式來結束執行緒的示例。儘管該示例的實用性不大。原因在 IBM的這篇博文中:我們 生吞了中斷。

在第14行,我們直接catch了異常,然後列印輸出了一下而已,呼叫棧中的更高層的程式碼是無法獲得關於該異常的資訊的。

第16行的e.printStackTrace()作用就相當於

“(僅僅記錄 InterruptedException 也不是明智的做法,因為等到人來讀取日誌的時候,再來對它作出處理就為時已晚了。)”---摘自參考博文

上面我們是在run()方法中丟擲異常,符合這裡描述的:

有時候丟擲 InterruptedException 並不合適,例如當由 Runnable 定義的任務呼叫一個
可中斷的方法時,就是如此。在這種情況下,不能重新丟擲 InterruptedException,但是
您也不想什麼都不做。當一個阻塞方法檢測到中斷並丟擲 InterruptedException 時,它
清除中斷狀態。如果捕捉到 InterruptedException 但是不能重新丟擲它,那麼應該保留
中斷髮生的證據,以便呼叫棧中更高層的程式碼能知道中斷,並對中斷作出響應。該任務可以
通過呼叫 interrupt() 以 “重新中斷” 當前執行緒來完成,如清單 3 所示。 -----“摘自參考博文”

因為,run方法是實現的Runnable介面中的方法。不能像下面這樣定義,也即上面所說的:“不能重新丟擲InterruptedException”。

        @Override
        public void run() throws InterruptedException{//這是錯誤的
          //do something...

因此,一個更好的解決方案是:呼叫 interrupt() 以 “重新中斷” 當前執行緒。改進MyThread類中catch異常的方式,如下:

 1 public class MyThread extends Thread {
 2     @Override
 3     public void run() {
 4         super.run();
 5         try{
 6             for (int i = 0; i < 500000; i++) {
 7                 if (this.interrupted()) {
 8                     System.out.println("should be stopped and exit");
 9                     throw new InterruptedException();
10                 }
11                 System.out.println("i=" + (i + 1));
12             }
13             System.out.println("this line cannot be executed. cause thread throws exception");
14         }catch(InterruptedException e){
15             /**這樣處理不好
16              * System.out.println("catch interrupted exception");
17              * e.printStackTrace();
18              */
19              Thread.currentThread().interrupt();//這樣處理比較好
20         }
21     }
22 }

這樣,就由 生吞異常 變成了 將 異常事件 進一步擴散了。

參考書籍:《Java多執行緒程式設計核心技術》

相關推薦

java執行機制

網上看到一個題目,題目是這樣:Java多執行緒,啟動四個執行緒,兩個執行加一,另外兩個執行減一。 針對該問題寫了一個程式,測試通過,如下: class Sync { static int count = 0; public void add() {

java執行機制

網上看了一篇關於java synchronized關鍵字使用的很好的文章,現將其簡要總結一下,加深理解。 先總結兩個規則: synchronized鎖住的是括號裡的物件,而不是程式碼。對於非static的synchronized方法,鎖的就是物件本身也就是this。 多個執行緒

JAVA執行中斷機制(如何處理中斷?)

一,介紹 這篇文章主要記錄使用 interrupt() 方法中斷執行緒,以及如何對InterruptedException進行處理。感覺對InterruptedException異常進行處理是一件謹慎且有技巧的活兒。 由於使用stop()方法停止執行緒非常的暴力,人家執行緒執行的好好的,突然就把人家殺死了

java執行等待喚醒機制(wait-notify)

wait()、notify()、notifyAll()方法 Object類裡面提供了這幾個方法: wait():讓當前執行緒處於等待(阻塞狀態),直到其他執行緒呼叫此物件的notify()或noti

Java執行執行個任務並處理所有結果

執行器框架給我們提供了一個方法,讓我們可以傳送給執行器一個任務列表,並等待任務列表中的所有任務執行完畢。然後它將返回一個與任務列表對應的Future列表。 package com.primer.d

Java執行三volatile與等待通知機制示例

原子性,可見性與有序性 在多執行緒中,執行緒同步的時候一般需要考慮原子性,可見性與有序性 原子性 原子性定義:一個操作或者多個操作在執行過程中要麼全部執行完成,要麼全部都不執行,不存在執行一部分的情況。 以我們在Java程式碼中經常用到的自增操作i++為例,i++實際上並不是一步操作,而是首先對i的值加一,然

java執行NIO的中斷

package com.eshroe.sweetop.concurrency; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; impor

Java執行執行中斷

取消任務的方式 Java中沒有提供任何機制來安全地終止執行緒,但是提供了中斷(Interruption)協作機制,能夠使一個執行緒終止另一個執行緒的當前工作. 一般取消或停止某個任務,很少採用立即停止,因為立即停止會使得共享資料結構出於不一致的狀態.這也是Th

Java執行執行間通訊--等待(wait)/通知(notify)機制,等待/通知交叉備份例項

1、什麼是等待/通知機制   等待/通知機制在生活中比比皆是,比如在就餐時就會出現,如圖所示。      廚師和服務員之間的互動要在“菜品傳遞臺”上,在這期間會有幾個問題:   1).廚師做完一道菜的時間不確定,所以廚師將菜品放到‘菜品傳遞言,上的時間也

Java執行join()方法

概要 本章,會對Thread中join()方法進行介紹。涉及到的內容包括: 1. join()介紹 2. join()原始碼分析(基於JDK1.7.0_40) 3. join()示例 來源:http://www.cnblogs.com/skywang12345/p/34792

白話理解java執行join()方法

join字面意思是加入,我理解為插隊. 舉例:媽媽在炒菜,發現沒喲醬油了,讓兒子去打醬油,兒子打完醬油,媽媽炒完菜,全家一起吃 package cn.yh.thread01; /** * * 打醬油的例子 */ public class Demo03 { public stat

細說Java 執行記憶體可見性

前言: 討論學習Java中的記憶體可見性、Java記憶體模型、指令重排序、as-if-serial語義等多執行緒中偏向底層的一些知識,以及synchronized和volatile實現記憶體可見性的原理和方法。 1、可見性介紹 可見性:一個執行緒對共用變數值的修改,能夠及時地被其他執行緒

java執行 執行協作

也是網上看的一道題目:關於假如有Thread1、Thread2、Thread3、Thread4四條執行緒分別統計C、D、E、F四個盤的大小,所有執行緒都統計完畢交給Thread5執行緒去做彙總,應當如何實現? 蒐集整理了網上朋友提供的方法,主要有: 1. 多執行緒都是Thread或

java執行Phaser

java多執行緒技術提供了Phaser工具類,Phaser表示“階段器”,用來解決控制多個執行緒分階段共同完成任務的情景問題。其作用相比CountDownLatch和CyclicBarrier更加靈活,例如有這樣的一個題目:5個學生一起參加考試,一共有三道題,要求所有學生到齊才能開始考試,全部同學都

Java執行——ThreadLocal

ThreadLocal是什麼:每一個ThreadLocal能夠放一個執行緒級別的變數,也就是說,每一個執行緒有獨自的變數,互不干擾。以此達到執行緒安全的目的,並且一定會安全。 實現原理: 要了解實現原理,我們先看set方法 public void set(T value) { T

java執行Lock--顯式鎖

Lock與Synchronized簡介 Synchornized相信大家用的已經比較熟悉了,這裡我就不介紹它的用法了 Synchronized被稱為同步鎖或者是隱式鎖,隱式鎖與顯式鎖區別在於,隱式鎖的獲取和釋放都需要出現在一個塊結構中,而且是有順序的,獲取鎖的順序和釋放鎖的順序必須相反,就是說,

Java執行Executor框架

在前面的這篇文章中介紹了執行緒池的相關知識,現在我們來看一下跟執行緒池相關的框架--Executor。 一.什麼是Executor 1.Executor框架的兩級排程模型 在HotSpot VM的執行緒模型中,Java執行緒(java.lang.Thread)被一對一對映為本地作業系統執

java執行中的異常處理

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

java執行Executor

程式 程序:執行的程式 執行緒:程序中負責程式執行的執行單元,一個程序至少包括一個執行緒。 單執行緒:一個程序一個執行緒 多執行緒:一個程序多個執行緒   多執行緒是為了更好的利用CPU,提高程式執行的速度。 實現方式:繼承Thread類、實現Runnabl

java執行(二)鎖

一,鎖 在物件的建立時java會為每個object物件分配一個monitor( 監視器或者監視鎖),當某個物件的同步方法(synchronized methods )被多個執行緒呼叫時,該物件的monitor將負責處理這些訪問的併發獨佔要求。 當一個執行緒呼叫一個物件的同步方法時(sy