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

Java的線程阻塞、中斷及優(yōu)雅退出方法詳解

 更新時(shí)間:2023年10月26日 09:54:55   作者:chengmaoning  
這篇文章主要介紹了Java的線程阻塞、中斷及優(yōu)雅退出方法詳解,Java中的線程阻塞是指當(dāng)一個(gè)線程無法繼續(xù)執(zhí)行時(shí),它會(huì)進(jìn)入阻塞狀態(tài),直到某個(gè)條件滿足后才能繼續(xù)執(zhí)行,線程阻塞可以通過多種方式實(shí)現(xiàn),需要的朋友可以參考下

線程阻塞

一個(gè)線程進(jìn)入阻塞狀態(tài)的原因可能如下(已排除Deprecated方法):

sleep()

sleep()使當(dāng)前線程進(jìn)入停滯狀態(tài)(阻塞當(dāng)前線程),讓出CUP的使用、目的是不讓當(dāng)前線程獨(dú)自霸占該進(jìn)程所獲的CPU資源,以留一定時(shí)間給其他線程執(zhí)行的機(jī)會(huì);

當(dāng)在一個(gè)Synchronized塊中調(diào)用Sleep()方法是,線程雖然休眠了,但是對象鎖并沒有被釋放,其他線程無法訪問這個(gè)對象(即使睡著也持有對象鎖)。

wait()

調(diào)用wait()/1.5中的condition.await()使線程掛起,直到線程獲取notify()/notifyAll()消息,(或者在Java SE5中java.util.concurrent類庫中等價(jià)的signal()/signalAll()消息),線程才會(huì)進(jìn)入就緒狀態(tài);

wait()調(diào)用會(huì)釋放當(dāng)前對象鎖(monitor),這樣其他線程可以繼續(xù)進(jìn)入對象的同步方法。

另外,調(diào)用join()也會(huì)導(dǎo)致線程阻塞,因?yàn)樵创a中join()就是通過wait()實(shí)現(xiàn)的;

等待I/O;

class Demo3 implements Runnable throws InterruptedException{
     private InputStream in;
     public void run(){
          in.read();
     }
}

無法持有鎖進(jìn)入同步代碼

進(jìn)入同步代碼前無法獲取鎖,比如試圖調(diào)用synchronized方法,或者顯示鎖對象的上鎖行為ReentrantLock.lock(),而對應(yīng)鎖已被其他線程獲取的情況下都將導(dǎo)致線程進(jìn)入阻塞狀態(tài);

注意:yield()并不會(huì)導(dǎo)致線程轉(zhuǎn)到等待/睡眠/阻塞狀態(tài)。在大多數(shù)情況下,yield()將導(dǎo)致線程從運(yùn)行狀態(tài)轉(zhuǎn)到可運(yùn)行狀態(tài),但有可能沒有效果。

線程中斷

線程中斷可以在線程內(nèi)部設(shè)置一個(gè)中斷標(biāo)識,同時(shí)讓處于(可中斷)阻塞的線程拋出InterruptedException中斷異常,使線程跳出阻塞狀態(tài)。相比其他語言,Java線程中斷比較特殊,經(jīng)常會(huì)引起開發(fā)人員的誤解。因?yàn)橹袛嗦犉饋砀呱顝?fù)雜,實(shí)質(zhì)原理上非常簡單。

中斷原理

Java中斷機(jī)制是一種協(xié)作機(jī)制,也就是說通過中斷并不能直接終止另一個(gè)線程,而需要被中斷的線程自己處理中斷。這好比是家里的父母叮囑在外的子女要注意身體,但子女是否注意身體,怎么注意身體則完全取決于自己。

Java中斷模型也是這么簡單,每個(gè)線程對象里都有一個(gè)boolean類型的標(biāo)識(不一定就要是Thread類的字段,實(shí)際上也的確不是,這幾個(gè)方法最終都是通過native方法來完成的),代表著是否有中斷請求(該請求可以來自所有線程,包括被中斷的線程本身)。例如,當(dāng)線程t1想中斷線程t2,只需要在線程t1中將線程t2對象的中斷標(biāo)識置為true,然后線程2可以選擇在合適的時(shí)候處理該中斷請求,甚至可以不理會(huì)該請求,就像這個(gè)線程沒有被中斷一樣。

中斷相關(guān)的方法

方法解釋
public static boolean interrupted()測試當(dāng)前線程是否已經(jīng)中斷。線程的中斷狀態(tài) 由該方法清除。換句話說,如果連續(xù)兩次調(diào)用該方法,則第二次調(diào)用將返回 false(在第一次調(diào)用已清除了其中斷狀態(tài)之后,且第二次調(diào)用檢驗(yàn)完中斷狀態(tài)前,當(dāng)前線程再次中斷的情況除外)。
public boolean isInterrupted()測試線程是否已經(jīng)中斷。線程的中斷狀態(tài)不受該方法的影響。
public void interrupt()中斷線程,設(shè)置中斷標(biāo)識為為true。

其中,interrupt方法是唯一能將中斷狀態(tài)設(shè)置為true的方法。靜態(tài)方法interrupted會(huì)將當(dāng)前線程的中斷狀態(tài)清除,但這個(gè)方法的命名極不直觀,很容易造成誤解,需要特別注意。

此外,類庫中的有些類的方法也可能會(huì)調(diào)用中斷,如FutureTask中的cancel方法,如果傳入的參數(shù)為true,它將會(huì)在正在運(yùn)行異步任務(wù)的線程上調(diào)用interrupt方法,如果正在執(zhí)行的異步任務(wù)中的代碼沒有對中斷做出響應(yīng),那么cancel方法中的參數(shù)將不會(huì)起到什么效果;

ExecutorService exec = Executors.newCachedThreadPool();
Futrue<?> f = exec.submit(new TaskThread());
f.interrupt();

又如ThreadPoolExecutor中的shutdownNow方法會(huì)遍歷線程池中的工作線程并調(diào)用線程的interrupt方法來中斷線程,所以如果工作線程中正在執(zhí)行的任務(wù)沒有對中斷做出響應(yīng),任務(wù)將一直執(zhí)行直到正常結(jié)束。

ExecutorService exec = Executors.newCachedThreadPool();
for(int i=0;i<5;i++)
     exec.execute(new TaskThread())
exec.shutdownNow();

中斷的處理

中斷一個(gè)線程只是為了引起該線程的注意,被中斷線程可以決定如何應(yīng)對中斷。某些線程非常重要,以至于它們應(yīng)該不理會(huì)中斷,而是在處理完拋出的異常之后繼續(xù)執(zhí)行,但是更普遍的情況是,一個(gè)線程將把中斷看作一個(gè)終止請求,這種線程的run方法遵循如下形式:

public void run() {
    try {
        ...
        /*
         * 不管循環(huán)里是否調(diào)用過線程阻塞的方法如sleep、join、wait,這里還是需要加上
         * !Thread.currentThread().isInterrupted()條件,雖然拋出異常后退出了循環(huán),顯
         * 得用阻塞的情況下是多余的,但如果調(diào)用了阻塞方法但沒有阻塞時(shí),這樣會(huì)更安全、更及時(shí)。
         */
        while (!Thread.currentThread().isInterrupted()&& more work to do) {
            do more work 
        }
    } catch (InterruptedException e) {
        //線程在wait或sleep期間被中斷了
    } finally {
        //線程結(jié)束前做一些清理工作
    }
}

上面是while循環(huán)在try塊里,如果try在while循環(huán)里時(shí),因該在catch塊里重新設(shè)置一下中斷標(biāo)示,因?yàn)閽伋鯥nterruptedException異常后,中斷標(biāo)示位會(huì)自動(dòng)清除,此時(shí)應(yīng)該這樣:

public void run() {
    while (!Thread.currentThread().isInterrupted()&& more work to do) {
        try {
            ...
            sleep(delay);
            //wait(delay);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();   //重新設(shè)置中斷標(biāo)示
        }
    }
}

可中斷阻塞

對于處于sleep,join等操作的線程,如果被調(diào)用interrupt()后,會(huì)拋出InterruptedException,然后線程的中斷標(biāo)志位會(huì)由true重置為false,因?yàn)榫€程為了處理異常已經(jīng)重新處于就緒狀態(tài)。

不可中斷的操作,包括進(jìn)入synchronized段以及Lock.lock(),inputSteam.read()等,調(diào)用interrupt()對于這幾個(gè)問題無效,因?yàn)樗鼈兌疾粧伋鲋袛喈惓?。如果拿不到資源,它們會(huì)無限期阻塞下去。

對于Lock.lock(),可以改用Lock.lockInterruptibly(),可被中斷的加鎖操作,它可以拋出中斷異常。等同于等待時(shí)間無限長的Lock.tryLock(long time, TimeUnit unit)。

對于inputStream等資源,有些(實(shí)現(xiàn)了interruptibleChannel接口)可以通過close()方法將資源關(guān)閉,對應(yīng)的阻塞也會(huì)被放開。

但是,你可能正使用Java1.0之前就存在的傳統(tǒng)的I/O,Thread.interrupt()將不起作用,因?yàn)榫€程將不會(huì)退出被阻塞狀態(tài)。

很幸運(yùn),Java平臺(tái)為這種情形提供了一項(xiàng)解決方案,即調(diào)用阻塞該線程的套接字的close()方法。在這種情形下,如果線程被I/O操作阻塞,當(dāng)調(diào)用該套接字的close方法時(shí),該線程在調(diào)用accept地方法將接收到一個(gè)SocketException(SocketException為IOException的子異常)異常,這與使用interrupt()方法引起一個(gè)InterruptedException異常被拋出非常相似。

java.nio類庫提供了更加人性化的I/O中斷,被阻塞的nio通道會(huì)自動(dòng)地響應(yīng)中斷,不需要關(guān)閉底層資源;

線程優(yōu)雅退出

一般情況下,線程退出可以使用while循環(huán)判斷共享變量條件的方式,當(dāng)線程內(nèi)有阻塞操作時(shí),可能導(dǎo)致線程無法運(yùn)行到條件判斷的地方而導(dǎo)致一直阻塞下去,這個(gè)時(shí)候就需要中斷來幫助線程脫離阻塞。因此比較優(yōu)雅的退出線程方式是結(jié)合共享變量和中斷。

thread = new Thread(new Runnable() {
    @Override
    public void run() {
        /*
         * 在這里為一個(gè)循環(huán),條件是判斷線程的中斷標(biāo)志位是否中斷
         */
        while (flag&&(!Thread.currentThread().isInterrupted())) {
            try {
                Log.i("tag","線程運(yùn)行中"+Thread.currentThread().getId());
                // 每執(zhí)行一次暫停40毫秒
                //當(dāng)sleep方法拋出InterruptedException  中斷狀態(tài)也會(huì)被清掉
                Thread.sleep(40);
            } catch (InterruptedException e) {
                e.printStackTrace();
                //如果拋出異常則再次設(shè)置中斷請求
                Thread.currentThread().interrupt();
            }
        }
    }
});
thread.start();

到此這篇關(guān)于Java的線程阻塞、中斷及優(yōu)雅退出方法詳解的文章就介紹到這了,更多相關(guān)Java線程阻塞、中斷及優(yōu)雅退出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • c#與java的相同點(diǎn)和不同點(diǎn)的詳細(xì)對比

    c#與java的相同點(diǎn)和不同點(diǎn)的詳細(xì)對比

    C#和Java是兩種廣泛應(yīng)用的面向?qū)ο缶幊陶Z言,它們在許多方面有相似之處,但也存在顯著的差異,這篇文章主要介紹了c#與java的相同點(diǎn)和不同點(diǎn)的詳細(xì)對比,需要的朋友可以參考下
    2025-07-07
  • Java JDK動(dòng)態(tài)代理實(shí)現(xiàn)原理實(shí)例解析

    Java JDK動(dòng)態(tài)代理實(shí)現(xiàn)原理實(shí)例解析

    這篇文章主要介紹了Java JDK動(dòng)態(tài)代理實(shí)現(xiàn)原理實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 使用SpringMVC接收文件流上傳和表單參數(shù)

    使用SpringMVC接收文件流上傳和表單參數(shù)

    這篇文章主要介紹了使用SpringMVC接收文件流上傳和表單參數(shù),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 基于mybatis like %%的問題

    基于mybatis like %%的問題

    這篇文章主要介紹了mybatis like %%的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Maven的聚合(多模塊)和Parent繼承

    Maven的聚合(多模塊)和Parent繼承

    今天小編就為大家分享一篇關(guān)于Maven的聚合(多模塊)和Parent繼承,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • 教你如何輕松學(xué)會(huì)Java快慢指針法

    教你如何輕松學(xué)會(huì)Java快慢指針法

    要想把搬磚的效率提高,我們肯定是逃不掉數(shù)據(jù)結(jié)構(gòu)和算法知識的,這不,可愛的小編今天就和大家一起學(xué)習(xí)來了,今天給大家分享的是快慢指針,那啥是快慢指針呢,文中有非常詳細(xì)的解釋,需要的朋友可以參考下
    2021-06-06
  • JavaWeb如何實(shí)現(xiàn)本地文件上傳功能

    JavaWeb如何實(shí)現(xiàn)本地文件上傳功能

    這篇文章主要介紹了JavaWeb如何實(shí)現(xiàn)本地文件上傳功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 使用Digester解析XML文件的三種方式小結(jié)

    使用Digester解析XML文件的三種方式小結(jié)

    Digester是apache開源項(xiàng)目Commons中的一個(gè)子項(xiàng)目,用于解析XML文檔的工具,本文為大家整理了Digester解析XML文件的三種方式,希望對大家有所幫助
    2024-01-01
  • SpringCloud Gateway之StripPrefix的使用方式

    SpringCloud Gateway之StripPrefix的使用方式

    這篇文章主要介紹了SpringCloud Gateway之StripPrefix的使用方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • 全面分析Java文件上傳

    全面分析Java文件上傳

    本片文章給大家詳細(xì)分析了Java文件上傳的相關(guān)知識點(diǎn),以及相關(guān)代碼做了詳細(xì)分析,有興趣的朋友學(xué)習(xí)下。
    2018-02-02

最新評論

英超| 蒲江县| 定日县| 宁阳县| 临夏县| 县级市| 定襄县| 阳原县| 西藏| 阿鲁科尔沁旗| 廉江市| 石泉县| 平顺县| 纳雍县| 固阳县| 定州市| 棋牌| 剑川县| 鹤壁市| 双峰县| 海城市| 玛纳斯县| 冀州市| 望谟县| 永城市| 北安市| 图木舒克市| 谢通门县| 怀柔区| 东平县| 通河县| 广安市| 清丰县| 揭东县| 襄樊市| 南康市| 齐齐哈尔市| 抚顺市| 东乌珠穆沁旗| 鹤山市| 肃宁县|