欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

線程阻塞

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

sleep()

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

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

wait()

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

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

另外,調(diào)用join()也會導(dǎo)致線程阻塞,因為源碼中join()就是通過wait()實現(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()并不會導(dǎo)致線程轉(zhuǎn)到等待/睡眠/阻塞狀態(tài)。在大多數(shù)情況下,yield()將導(dǎo)致線程從運行狀態(tài)轉(zhuǎn)到可運行狀態(tài),但有可能沒有效果。

線程中斷

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

中斷原理

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

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

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

方法解釋
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()中斷線程,設(shè)置中斷標(biāo)識為為true。

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

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

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

又如ThreadPoolExecutor中的shutdownNow方法會遍歷線程池中的工作線程并調(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();

中斷的處理

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

public void run() {
    try {
        ...
        /*
         * 不管循環(huán)里是否調(diào)用過線程阻塞的方法如sleep、join、wait,這里還是需要加上
         * !Thread.currentThread().isInterrupted()條件,雖然拋出異常后退出了循環(huán),顯
         * 得用阻塞的情況下是多余的,但如果調(diào)用了阻塞方法但沒有阻塞時,這樣會更安全、更及時。
         */
        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)里時,因該在catch塊里重新設(shè)置一下中斷標(biāo)示,因為拋出InterruptedException異常后,中斷標(biāo)示位會自動清除,此時應(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()后,會拋出InterruptedException,然后線程的中斷標(biāo)志位會由true重置為false,因為線程為了處理異常已經(jīng)重新處于就緒狀態(tài)。

不可中斷的操作,包括進(jìn)入synchronized段以及Lock.lock(),inputSteam.read()等,調(diào)用interrupt()對于這幾個問題無效,因為它們都不拋出中斷異常。如果拿不到資源,它們會無限期阻塞下去。

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

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

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

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

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

線程優(yōu)雅退出

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

thread = new Thread(new Runnable() {
    @Override
    public void run() {
        /*
         * 在這里為一個循環(huán),條件是判斷線程的中斷標(biāo)志位是否中斷
         */
        while (flag&&(!Thread.currentThread().isInterrupted())) {
            try {
                Log.i("tag","線程運行中"+Thread.currentThread().getId());
                // 每執(zhí)行一次暫停40毫秒
                //當(dāng)sleep方法拋出InterruptedException  中斷狀態(tài)也會被清掉
                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)文章

  • springboot項目整合注冊功能模塊開發(fā)實戰(zhàn)

    springboot項目整合注冊功能模塊開發(fā)實戰(zhàn)

    這篇文章主要介紹了springboot項目整合注冊功能模塊開發(fā)實戰(zhàn),在用戶的注冊是首先需要查詢當(dāng)前的用戶名是否存在,如果存在則不能進(jìn)行注冊,相當(dāng)于一個查詢語句,本文通過實例代碼詳細(xì)講解,需要的朋友可以參考下
    2022-11-11
  • 使用jd-gui反編譯修改jar包里的.class并重新生成新jar問題

    使用jd-gui反編譯修改jar包里的.class并重新生成新jar問題

    這篇文章主要介紹了使用jd-gui反編譯修改jar包里的.class并重新生成新jar問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Core Java 簡單談?wù)凥ashSet(推薦)

    Core Java 簡單談?wù)凥ashSet(推薦)

    下面小編就為大家?guī)硪黄狢ore Java 簡單談?wù)凥ashSet(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 自定義starter引發(fā)的線上事故記錄復(fù)盤

    自定義starter引發(fā)的線上事故記錄復(fù)盤

    這篇文章主要為大家介紹了自定義starter引發(fā)的線上事故記錄復(fù)盤,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Java for each實現(xiàn)機(jī)制代碼原理解析

    Java for each實現(xiàn)機(jī)制代碼原理解析

    這篇文章主要介紹了Java for each實現(xiàn)機(jī)制代碼原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • Java程序命令行參數(shù)用法總結(jié)

    Java程序命令行參數(shù)用法總結(jié)

    這篇文章主要介紹了Java程序命令行參數(shù)用法總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot?AOP?Redis實現(xiàn)延時雙刪功能實戰(zhàn)

    SpringBoot?AOP?Redis實現(xiàn)延時雙刪功能實戰(zhàn)

    本文主要介紹了SpringBoot?AOP?Redis實現(xiàn)延時雙刪功能實戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • SpringBoot中Session的使用及說明

    SpringBoot中Session的使用及說明

    這篇文章主要介紹了SpringBoot中Session的使用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Mybatis 緩存原理及失效情況解析

    Mybatis 緩存原理及失效情況解析

    這篇文章主要介紹了Mybatis 緩存原理及失效情況解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • SpringBoot2底層注解@Configuration配置類詳解

    SpringBoot2底層注解@Configuration配置類詳解

    這篇文章主要為大家介紹了SpringBoot2底層注解@Configuration配置類詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05

最新評論