最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java線程中斷的本質(zhì)深入理解

 更新時間:2012年12月03日 10:02:01   作者:  
Java的中斷是一種協(xié)作機制。也就是說調(diào)用線程對象的interrupt方法并不一定就中斷了正在運行的線程,它只是要求線程自己在合適的時機中斷自己,本文將詳細介紹,需要了解的朋友可以參考下
一、Java中斷的現(xiàn)象
首先,看看Thread類里的幾個方法:
public static boolean interrupted 測試當(dāng)前線程是否已經(jīng)中斷。線程的中斷狀態(tài) 由該方法清除。換句話說,如果連續(xù)兩次調(diào)用該方法,則第二次調(diào)用將返回 false(在第一次調(diào)用已清除了其中斷狀態(tài)之后,且第二次調(diào)用檢驗完中斷狀態(tài)前,當(dāng)前線程再次中斷的情況除外)。
public boolean isInterrupted() 測試線程是否已經(jīng)中斷。線程的中斷狀態(tài) 不受該方法的影響。
public void interrupt() 中斷線程。

上面列出了與中斷有關(guān)的幾個方法及其行為,可以看到interrupt是中斷線程。如果不了解Java的中斷機制,這樣的一種解釋極容易造成誤解,認(rèn)為調(diào)用了線程的interrupt方法就一定會中斷線程。
其實,Java的中斷是一種協(xié)作機制。也就是說調(diào)用線程對象的interrupt方法并不一定就中斷了正在運行的線程,它只是要求線程自己在合適的時機中斷自己。每個線程都有一個boolean的中斷狀態(tài)(不一定就是對象的屬性,事實上,該狀態(tài)也確實不是Thread的字段),interrupt方法僅僅只是將該狀態(tài)置為true
復(fù)制代碼 代碼如下:

public class TestInterrupt {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
t.interrupt();
System.out.println("已調(diào)用線程的interrupt方法");
}
static class MyThread extends Thread {
public void run() {
int num = longTimeRunningNonInterruptMethod(2, 0);
System.out.println("長時間任務(wù)運行結(jié)束,num=" + num);
System.out.println("線程的中斷狀態(tài):" + Thread.interrupted());
}
private static int longTimeRunningNonInterruptMethod(int count, int initNum) {
for(int i=0; i<count; i++) {
for(int j=0; j<Integer.MAX_VALUE; j++) {
initNum ++;
}
}
return initNum;
}
}
}

一般情況下,會打印如下內(nèi)容:
已調(diào)用線程的interrupt方法
長時間任務(wù)運行結(jié)束,num=-2
線程的中斷狀態(tài):true
可見,interrupt方法并不一定能中斷線程。但是,如果改成下面的程序,情況會怎樣呢?
復(fù)制代碼 代碼如下:

import java.util.concurrent.TimeUnit;
public class TestInterrupt {
public static void main(String[] args) {
Thread t = new MyThread();
t.start();
t.interrupt();
System.out.println("已調(diào)用線程的interrupt方法");
}
static class MyThread extends Thread {
public void run() {
int num = -1;
try {
num = longTimeRunningInterruptMethod(2, 0);
} catch (InterruptedException e) {
System.out.println("線程被中斷");
throw new RuntimeException(e);
}
System.out.println("長時間任務(wù)運行結(jié)束,num=" + num);
System.out.println("線程的中斷狀態(tài):" + Thread.interrupted());
}
private static int longTimeRunningInterruptMethod(int count, int initNum) throws InterruptedException{
for(int i=0; i<count; i++) {
TimeUnit.SECONDS.sleep(5);
}
return initNum;
}
}
}

經(jīng)運行可以發(fā)現(xiàn),程序拋出異常停止了,run方法里的后兩條打印語句沒有執(zhí)行。那么,區(qū)別在哪里?
一般說來,如果一個方法聲明拋出InterruptedException,表示該方法是可中斷的(沒有在方法中處理中斷卻也聲明拋出InterruptedException的除外),也就是說可中斷方法會對interrupt調(diào)用做出響應(yīng)(例如sleep響應(yīng)interrupt的操作包括清除中斷狀態(tài),拋出InterruptedException),如果interrupt調(diào)用是在可中斷方法之前調(diào)用,可中斷方法一定會處理中斷,像上面的例子,interrupt方法極可能在run未進入sleep的時候就調(diào)用了,但sleep檢測到中斷,就會處理該中斷。如果在可中斷方法正在執(zhí)行中的時候調(diào)用interrupt,會怎么樣呢?這就要看可中斷方法處理中斷的時機了,只要可中斷方法能檢測到中斷狀態(tài)為true,就應(yīng)該處理中斷。讓我們?yōu)殚_頭的那段代碼加上中斷處理。
那么自定義的可中斷方法該如何處理中斷呢?那就是在適合處理中斷的地方檢測線程中斷狀態(tài)并處理。
復(fù)制代碼 代碼如下:

public class TestInterrupt {
public static void main(String[] args) throws Exception {
Thread t = new MyThread();
t.start();
// TimeUnit.SECONDS.sleep(1);//如果不能看到處理過程中被中斷的情形,可以啟用這句再看看效果
t.interrupt();
System.out.println("已調(diào)用線程的interrupt方法");
}
static class MyThread extends Thread {
public void run() {
int num;
try {
num = longTimeRunningNonInterruptMethod(2, 0);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("長時間任務(wù)運行結(jié)束,num=" + num);
System.out.println("線程的中斷狀態(tài):" + Thread.interrupted());
}
private static int longTimeRunningNonInterruptMethod(int count, int initNum) throws InterruptedException {
if(interrupted()) {
throw new InterruptedException("正式處理前線程已經(jīng)被請求中斷");
}
for(int i=0; i<count; i++) {
for(int j=0; j<Integer.MAX_VALUE; j++) {
initNum ++;
}
//假如這就是一個合適的地方
if(interrupted()) {
//回滾數(shù)據(jù),清理操作等
throw new InterruptedException("線程正在處理過程中被中斷");
}
}
return initNum;
}
}
}

如上面的代碼,方法longTimeRunningMethod此時已是一個可中斷的方法了。在進入方法的時候判斷是否被請求中斷,如果是,就不進行相應(yīng)的處理了;處理過程中,可能也有合適的地方處理中斷,例如上面最內(nèi)層循環(huán)結(jié)束后。
這段代碼中檢測中斷用了Thread的靜態(tài)方法interrupted,它將中斷狀態(tài)置為false,并將之前的狀態(tài)返回,而isInterrupted只是檢測中斷,并不改變中斷狀態(tài)。一般來說,處理過了中斷請求,應(yīng)該將其狀態(tài)置為false。但具體還要看實際情形。

二、Java中斷的本質(zhì)
在歷史上,Java試圖提供過搶占式限制中斷,但問題多多,例如已被廢棄的Thread.stop、Thread.suspend和 Thread.resume等。另一方面,出于Java應(yīng)用代碼的健壯性的考慮,降低了編程門檻,減少不清楚底層機制的程序員無意破壞系統(tǒng)的概率。
如今,Java的線程調(diào)度不提供搶占式中斷,而采用協(xié)作式的中斷。其實,協(xié)作式的中斷,原理很簡單,就是輪詢某個表示中斷的標(biāo)記,我們在任何普通代碼的中都可以實現(xiàn)。 例如下面的代碼:
復(fù)制代碼 代碼如下:

volatile bool isInterrupted;
//…
while(!isInterrupted) {
compute();
}

但是,上述的代碼問題也很明顯。當(dāng)compute執(zhí)行時間比較長時,中斷無法及時被響應(yīng)。另一方面,利用輪詢檢查標(biāo)志變量的方式,想要中斷wait和sleep等線程阻塞操作也束手無策。
如果仍然利用上面的思路,要想讓中斷及時被響應(yīng),必須在虛擬機底層進行線程調(diào)度的對標(biāo)記變量進行檢查。是的,JVM中確實是這樣做的。下面摘自java.lang.Thread的源代碼:
復(fù)制代碼 代碼如下:

public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
//…
private native boolean isInterrupted(boolean ClearInterrupted);

可以發(fā)現(xiàn),isInterrupted被聲明為native方法,取決于JVM底層的實現(xiàn)。
實際上,JVM內(nèi)部確實為每個線程維護了一個中斷標(biāo)記。但應(yīng)用程序不能直接訪問這個中斷變量,必須通過下面幾個方法進行操作:
復(fù)制代碼 代碼如下:

public class Thread {
//設(shè)置中斷標(biāo)記
public void interrupt() { ... }
//獲取中斷標(biāo)記的值
public boolean isInterrupted() { ... }
//清除中斷標(biāo)記,并返回上一次中斷標(biāo)記的值
public static boolean interrupted() { ... }
...
}

通常情況下,調(diào)用線程的interrupt方法,并不能立即引發(fā)中斷,只是設(shè)置了JVM內(nèi)部的中斷標(biāo)記。因此,通過檢查中斷標(biāo)記,應(yīng)用程序可以做一些特殊操作,也可以完全忽略中斷。

你可能想,如果JVM只提供了這種簡陋的中斷機制,那和應(yīng)用程序自己定義中斷變量并輪詢的方法相比,基本也沒有什么優(yōu)勢。

JVM內(nèi)部中斷變量的主要優(yōu)勢,就是對于某些情況,提供了模擬自動“中斷陷入”的機制。
在執(zhí)行涉及線程調(diào)度的阻塞調(diào)用時(例如wait、sleep和join),如果發(fā)生中斷,被阻塞線程會“盡可能快的”拋出InterruptedException。因此,我們就可以用下面的代碼框架來處理線程阻塞中斷:
復(fù)制代碼 代碼如下:

try {
//wait、sleep或join
}
catch(InterruptedException e) {
//某些中斷處理工作
}

所謂“盡可能快”,我猜測JVM就是在線程調(diào)度調(diào)度的間隙檢查中斷變量,速度取決于JVM的實現(xiàn)和硬件的性能。

三、一些不會拋出 InterruptedException 的線程阻塞操作
然而,對于某些線程阻塞操作,JVM并不會自動拋出InterruptedException異常。例如,某些I/O操作和內(nèi)部鎖操作。對于這類操作,可以用其他方式模擬中斷:
1)java.io中的異步socket I/O
讀寫socket的時候,InputStream和OutputStream的read和write方法會阻塞等待,但不會響應(yīng)java中斷。不過,調(diào)用Socket的close方法后,被阻塞線程會拋出SocketException異常。
2)利用Selector實現(xiàn)的異步I/O
如果線程被阻塞于Selector.select(在java.nio.channels中),調(diào)用wakeup方法會引起ClosedSelectorException異常。
3)鎖獲取
如果線程在等待獲取一個內(nèi)部鎖,我們將無法中斷它。但是,利用Lock類的lockInterruptibly方法,我們可以在等待鎖的同時,提供中斷能力。

四、兩條編程原則
另外,在任務(wù)與線程分離的框架中,任務(wù)通常并不知道自身會被哪個線程調(diào)用,也就不知道調(diào)用線程處理中斷的策略。所以,在任務(wù)設(shè)置了線程中斷標(biāo)記后,并不能確保任務(wù)會被取消。因此,有以下兩條編程原則:
1)除非你知道線程的中斷策略,否則不應(yīng)該中斷它。
這條原則告訴我們,不應(yīng)該直接調(diào)用Executer之類框架中線程的interrupt方法,應(yīng)該利用諸如Future.cancel的方法來取消任務(wù)。

2)任務(wù)代碼不該猜測中斷對執(zhí)行線程的含義。
這條原則告訴我們,一般代碼遇在到InterruptedException異常時,不應(yīng)該將其捕獲后“吞掉”,而應(yīng)該繼續(xù)向上層代碼拋出。
總之,Java中的非搶占式中斷機制,要求我們必須改變傳統(tǒng)的搶占式中斷思路,在理解其本質(zhì)的基礎(chǔ)上,采用相應(yīng)的原則和模式來編程。

相關(guān)文章

  • 詳解Java Proxy動態(tài)代理機制

    詳解Java Proxy動態(tài)代理機制

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著Java動態(tài)代理機制展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • MyBatis-Puls插入或修改時某些字段自動填充操作示例

    MyBatis-Puls插入或修改時某些字段自動填充操作示例

    這篇文章主要為大家介紹了MyBatis-Puls插入或修改時某些字段自動填充操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Spring的編程式事務(wù)TransactionTemplate的用法詳解

    Spring的編程式事務(wù)TransactionTemplate的用法詳解

    TransactionTemplate提供了一種在代碼中進行編程式事務(wù)管理的方式,使開發(fā)人員能夠在方法級別定義事務(wù)的開始和結(jié)束點,本文介紹了Spring框架中TransactionTemplate的用法,感興趣的朋友跟隨小編一起看看吧
    2023-07-07
  • jar包運行時提示jar中沒有主清單屬性的解決

    jar包運行時提示jar中沒有主清單屬性的解決

    這篇文章主要介紹了jar包運行時提示jar中沒有主清單屬性的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 分析Java中ArrayList與LinkedList列表結(jié)構(gòu)的源碼

    分析Java中ArrayList與LinkedList列表結(jié)構(gòu)的源碼

    這篇文章主要介紹了Java中ArrayList與LinkedList列表結(jié)構(gòu)的源碼,文章最后對LinkedList和ArrayList以及Vector的特性有一個對比總結(jié),需要的朋友可以參考下
    2016-05-05
  • java校驗json的格式是否符合要求的操作方法

    java校驗json的格式是否符合要求的操作方法

    在日常開發(fā)過程中,會有這樣的需求,校驗?zāi)硞€json是否是我們想要的數(shù)據(jù)格式,這篇文章主要介紹了java校驗json的格式是否符合要求,需要的朋友可以參考下
    2023-04-04
  • Java之ThreadPoolExecutor類詳解

    Java之ThreadPoolExecutor類詳解

    這篇文章主要介紹了Java之ThreadPoolExecutor類詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java基礎(chǔ)知識精通各種運算符

    Java基礎(chǔ)知識精通各種運算符

    計算機的最基本用途之一就是執(zhí)行數(shù)學(xué)運算,作為一門計算機語言,Java也提供了一套豐富的運算符來操縱變量,本篇對大家的學(xué)習(xí)或工作具有一定的價值,需要的朋友可以參考下
    2022-04-04
  • java如何使用自己的maven本地倉庫詳解

    java如何使用自己的maven本地倉庫詳解

    這篇文章主要給大家介紹了關(guān)于java如何使用自己的maven本地倉庫的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • Java AWT中常用的三種布局管理器詳解

    Java AWT中常用的三種布局管理器詳解

    這篇文章主要介紹了Java AWT中常用的三種布局管理器詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12

最新評論

雅安市| 吴桥县| 肃北| 独山县| 新泰市| 呼伦贝尔市| 克拉玛依市| 莱阳市| 安远县| 白山市| 金坛市| 齐齐哈尔市| 顺昌县| 曲沃县| 吉隆县| 若尔盖县| 武鸣县| 柘荣县| 河间市| 布拖县| 招远市| 唐海县| 古蔺县| 万年县| 永靖县| 临桂县| 手游| 广东省| 黎城县| 韶关市| 佛教| 北海市| 崇义县| 墨脱县| 包头市| 谷城县| 西乌珠穆沁旗| 合作市| 乌拉特中旗| 岑巩县| 新源县|