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

Java正確停止線程的常見(jiàn)方式詳解

 更新時(shí)間:2025年08月20日 10:32:25   作者:程序員小假  
對(duì)于 Java 而言,最正確的停止線程的方式是使用?interrupt,但?interrupt僅僅起到通知被停止線程的作用,那么如何正確停掉線程呢,本文給大家介紹了Java正確停止線程的常見(jiàn)方式,需要的朋友可以參考下

為什么不強(qiáng)制停止

對(duì)于 Java 而言,最正確的停止線程的方式是使用 interrupt。但 interrupt僅僅起到通知被停止線程的作用。而對(duì)于被停止的線程而言,它擁有完全的自主 權(quán),它既可以選擇立即停止,也可以選擇一段時(shí)間后停止,也可以選擇壓根不停止。 

為什么 Java 不提供強(qiáng)制停止線程的能力呢?

事實(shí)上,Java 希望程序間能夠相互通知、相互協(xié)作地管理線程,因?yàn)槿绻涣私鈱?duì)方正在做的工作,貿(mào)然強(qiáng)制停止線程就可能會(huì)造成一些安全的問(wèn)題。

比如:

線程正在寫(xiě)入一個(gè)文件,這時(shí)收到終止信號(hào),它就需要根據(jù)自身業(yè)務(wù)判斷,是選擇立即停止,還是將整個(gè)文件寫(xiě)入成功后停止。如果選擇立即停止就可能造成數(shù)據(jù)不完整,不管是中斷命令發(fā)起者,還是接收者都不希望數(shù)據(jù)出現(xiàn)問(wèn)題。 

如何用 interrupt 停止線程

while (!Thread.currentThread().isInterrupted() 
&& more work to do) {
    do more work
}

一旦調(diào)用某個(gè)線程的 interrupt() 之后,這個(gè)線程的中斷標(biāo)記位就會(huì)被設(shè)置成 true。每個(gè)線程都有這樣的標(biāo)記位,當(dāng)線程執(zhí)行時(shí),應(yīng)該定期檢查這個(gè)標(biāo)記位,如果標(biāo)記位被設(shè)置成 true,就說(shuō)明有程序想終止該線程。
回到源碼,可以看到在 while 循環(huán)體判斷語(yǔ)句中,首先通過(guò) Thread.currentThread().isInterrupt() 判斷線程是否被中斷,隨后檢查是否還有工作要做。&& 邏輯表示只有當(dāng)兩個(gè)判斷條件同時(shí)滿足的情況下,才會(huì)去執(zhí)行下面的工作。
來(lái)段代碼瞅瞅。

public class StopThread implements Runnable {
    @Override
    public void run() {
        int count = 0;
        while (!Thread.currentThread().isInterrupted() && count < 1000) {
            System.out.println("count = " + count++);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new StopThread());
        thread.start();
        Thread.sleep(5);
        thread.interrupt();
    }
}

在 StopThread 類的 run() 方法中,首先判斷線程是否被中斷,然后判斷 count 值是否小于 1000。
這個(gè)線程的工作內(nèi)容很簡(jiǎn)單,就是打印 0~999 的數(shù)字,每打印一個(gè)數(shù)字 count 值加 1,可以看到,線程會(huì)在每次循環(huán)開(kāi)始之前,檢查是否被中斷了。接下來(lái)在 main 函數(shù)中會(huì)啟動(dòng)該線程,然后休眠 5 毫秒后立刻中斷線程,該線程會(huì)檢測(cè)到中斷信號(hào),于是在還沒(méi)打印完1000個(gè)數(shù)的時(shí)候就會(huì)停下來(lái),這種就屬于通過(guò) interrupt 正確停止線程的情況。 

sleep 期間能否感受到中斷

先說(shuō)結(jié)論,可以。

public class StopDuringSleep {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = () -> {
            int num = 0;
            try {
                while (!Thread.currentThread().isInterrupted() && num <= 1000) {
                    System.out.println(num);
                    num++;
                    Thread.sleep(1000000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
        Thread.sleep(5);
        thread.interrupt();
    }
}

運(yùn)行后的結(jié)果猜這么著,程序會(huì)拋出異常

如果 sleep、wait 等可以讓線程進(jìn)入阻塞的方法使線程休眠了,而處于休眠中的線程被中斷,那么線程是可以感受到中斷信號(hào)的,并且會(huì)拋出一個(gè) InterruptedException 異常,同時(shí)清除中斷信號(hào),將中斷標(biāo)記位設(shè)置成 false。這樣一來(lái)就不用擔(dān)心長(zhǎng)時(shí)間休眠中線程感受不到中斷了,因?yàn)榧幢憔€程還在休眠,仍然能夠響應(yīng)中斷通知,并拋出異常。

但是這樣只能相應(yīng)一次中斷信號(hào)了,怎么辦? 

合理利用好 try/catch

在實(shí)際開(kāi)發(fā)中不能盲目吞掉中斷,如果不在方法簽名中聲明,也不在 catch 語(yǔ)句塊中再次恢復(fù)中斷,而是在 catch 中不作處理,稱這種行為是“屏蔽了中斷請(qǐng)求”。如果盲目地屏蔽了中斷請(qǐng)求,會(huì)導(dǎo)致中斷信號(hào)被完全忽略,最終導(dǎo)致線程無(wú)法正確停止。

try {
    Thread.sleep(2000);
} catch (InterruptedException e) {
//        此處處理中斷異常請(qǐng)求
}

停止線程的方式有幾種

  • void shutdown;
  • boolean isShutdown;
  • boolean isTerminated;
  • boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
  • List<Runnable> shutdownNow;

下面就對(duì)這些方法逐一展開(kāi)。 

shutdown()

調(diào)用 shutdown() 方法之后線程池并不是立刻就被關(guān)閉,因?yàn)檫@時(shí)線程池中可能還有很多任務(wù)正在被執(zhí)行,或是任務(wù)隊(duì)列中有大量正在等待被執(zhí)行的任務(wù),調(diào)用 shutdown() 方法后線程池會(huì)在執(zhí)行完正在執(zhí)行的任務(wù)和隊(duì)列中等待的任務(wù)后才徹底關(guān)閉。

但這并不代表 shutdown() 操作是沒(méi)有任何效果的,調(diào)用 shutdown() 方法后如果還有新的任務(wù)被提交,線程池則會(huì)根據(jù)拒絕策略直接拒絕后續(xù)新提交的任務(wù)。 

isShutdown()

它可以返回 true 或者 false 來(lái)判斷線程池是否已經(jīng)開(kāi)始了關(guān)閉工作,也就是是否執(zhí)行了 shutdown 或者 shutdownNow 方法。這里需要注意,如果調(diào)用 isShutdown() 方法的返回的結(jié)果為 true 并不代表線程池此時(shí)已經(jīng)徹底關(guān)閉了,這僅僅代表線程池開(kāi)始了關(guān)閉的流程,也就是說(shuō),此時(shí)可能線程池中依然有線程在執(zhí)行任務(wù),隊(duì)列里也可能有等待被執(zhí)行的任務(wù)。 

isTerminated()

這個(gè)方法可以檢測(cè)線程池是否真正“終結(jié)”了,這不僅代表線程池已關(guān)閉,同時(shí)代表線程池中的所有任務(wù)都已經(jīng)都執(zhí)行完畢了,因?yàn)閯偛耪f(shuō)過(guò),調(diào)用 shutdown 方法之后,線程池會(huì)繼續(xù)執(zhí)行里面未完成的任務(wù),不僅包括線程正在執(zhí)行的任務(wù),還包括正在任務(wù)隊(duì)列中等待的任務(wù)。
比如此時(shí)已經(jīng)調(diào)用了 shutdown 方法,但是有一個(gè)線程依然在執(zhí)行任務(wù),那么此時(shí)調(diào)用 isShutdown 方法返回的是 true ,而調(diào)用 isTerminated 方法返回的便是 false ,因?yàn)榫€程池中還有任務(wù)正在在被執(zhí)行,線程池并沒(méi)有真正“終結(jié)”。直到所有任務(wù)都執(zhí)行完畢了,調(diào)用 isTerminated() 方法才會(huì)返回 true,這表示線程池已關(guān)閉并且線程池內(nèi)部是空的,所有剩余的任務(wù)都執(zhí)行完畢了。 

awaitTermination()

第四個(gè)方法叫作 awaitTermination(),它本身并不是用來(lái)關(guān)閉線程池的,而是主要用來(lái)判斷線程池狀態(tài)的。比如給 awaitTermination 方法傳入的參數(shù)是 10 秒,那么它就會(huì)陷入 10 秒鐘的等待,直到發(fā)生以下三種情況之一:

  • 等待期間(包括進(jìn)入等待狀態(tài)之前)線程池已關(guān)閉并目所有已提交的任務(wù)(包括正在執(zhí)行的和隊(duì)列中等待的都執(zhí)行完畢,相當(dāng)于線程池已經(jīng)“終結(jié)”了,方法便會(huì)返回true
  • 等待超時(shí)時(shí)間到后,第一種線程池“終結(jié)”的情況始終未發(fā)生,方法返回 false
  • 等待期間線程被中斷,方法會(huì)拋出 Interruptedexception異常

等待期間(包括進(jìn)入等待狀態(tài)之前)線程池已關(guān)閉并且所有已提交的任務(wù)(包括正在執(zhí)行的和隊(duì)列中等待的)都執(zhí)行完畢,相當(dāng)于線程池已經(jīng)“終結(jié)”了,方法便會(huì)返回 true;
等待超時(shí)時(shí)間到后,第一種線程池“終結(jié)”的情況始終未發(fā)生,方法返回 false;等待期間線程被中斷,方法會(huì)拋出 InterruptedException 異常。 

shutdownNow()

最后一個(gè)方法是 shutdownNow(),也是 5 種方法里功能最強(qiáng)大的,它與第一種 shutdown 方法不同之處在于名字中多了一個(gè)單詞 Now,也就是表示立刻關(guān)閉的意思。
在執(zhí)行 shutdownNow 方法之后,首先會(huì)給所有線程池中的線程發(fā)送 interrupt 中斷信號(hào),嘗試中斷這些任務(wù)的執(zhí)行,然后會(huì)將任務(wù)隊(duì)列中正在等待的所有任務(wù)轉(zhuǎn)移到一個(gè) List 中并返回,可以根據(jù)返回的任務(wù) List 來(lái)進(jìn)行一些補(bǔ)救的操作,例如記錄在案并在后期重試。

public List<Runnable> shutdownNow() { 
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try { 
        checkShutdownAccess();
        advanceRunState(STOP);
        interruptWorkers();
        tasks = drainQueue();
    } finally { 
        mainLock.unlock();
    } 
    tryTerminate();
    return tasks;
 }

源碼中有一行 interruptWorkers() 代碼,這行代碼會(huì)讓每一個(gè)已經(jīng)啟動(dòng)的線程都中斷,這樣線程就可以在執(zhí)行任務(wù)期間檢測(cè)到中斷信號(hào)并進(jìn)行相應(yīng)的處理,提前結(jié)束任務(wù)。
這里需要注意的是,由于 Java 中不推薦強(qiáng)行停止線程的機(jī)制的限制,即便調(diào)用了 shutdownNow 方法,如果被中斷的線程對(duì)于中斷信號(hào)不理不睬,那么依然有可能導(dǎo)致任務(wù)不會(huì)停止。 

總結(jié)

中斷和關(guān)閉線程的方式五花八門(mén),看起來(lái)很相似,其實(shí)里頭大有門(mén)道。處理不好,可是會(huì)導(dǎo)致程序崩潰的。

以上就是Java正確停止線程的常見(jiàn)方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Java停止線程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Maven包沖突導(dǎo)致NoSuchMethodError錯(cuò)誤的解決辦法

    Maven包沖突導(dǎo)致NoSuchMethodError錯(cuò)誤的解決辦法

    web 項(xiàng)目 能正常編譯,運(yùn)行時(shí)也正常啟動(dòng),但執(zhí)行到需要調(diào)用 org.codehaus.jackson 包中的某個(gè)方法時(shí),產(chǎn)生運(yùn)行異常,這篇文章主要介紹了Maven包沖突導(dǎo)致NoSuchMethodError錯(cuò)誤的解決辦法,需要的朋友可以參考下
    2024-05-05
  • drools中使用function的方法小結(jié)

    drools中使用function的方法小結(jié)

    當(dāng)我們?cè)赿rools中編寫(xiě)規(guī)則時(shí),有些時(shí)候存在重復(fù)的代碼,那么我們是否可以將這些重復(fù)代碼抽取出來(lái),封裝成一個(gè)function來(lái)調(diào)用呢?那么在drools中如何自定義function?下面小編給大家介紹下drools中使用function的方法,需要的朋友可以參考下
    2022-05-05
  • Java設(shè)計(jì)模塊系列之書(shū)店管理系統(tǒng)單機(jī)版(一)

    Java設(shè)計(jì)模塊系列之書(shū)店管理系統(tǒng)單機(jī)版(一)

    這篇文章主要為大家詳細(xì)介紹了Java單機(jī)版的書(shū)店管理系統(tǒng)設(shè)計(jì)模塊和思想第一章,感興趣的小伙伴們可以參考一下
    2016-08-08
  • java swing標(biāo)準(zhǔn)對(duì)話框具體實(shí)現(xiàn)

    java swing標(biāo)準(zhǔn)對(duì)話框具體實(shí)現(xiàn)

    這篇文章介紹了swing標(biāo)準(zhǔn)對(duì)話框的具體實(shí)現(xiàn)方法,有需要的朋友可以參考一下
    2013-06-06
  • SpringBoot全局異常攔截與自定義錯(cuò)誤頁(yè)面實(shí)現(xiàn)過(guò)程解讀

    SpringBoot全局異常攔截與自定義錯(cuò)誤頁(yè)面實(shí)現(xiàn)過(guò)程解讀

    本文介紹了SpringBoot中全局異常攔截與自定義錯(cuò)誤頁(yè)面的實(shí)現(xiàn)方法,包括異常的分類、SpringBoot默認(rèn)異常處理機(jī)制、全局異常攔截實(shí)現(xiàn)、自定義錯(cuò)誤頁(yè)面實(shí)現(xiàn)以及兩者的結(jié)合使用,通過(guò)這些技術(shù),可以提高系統(tǒng)的穩(wěn)定性和用戶體驗(yàn)
    2025-12-12
  • Java中Byte數(shù)組與InputStream相互轉(zhuǎn)換實(shí)現(xiàn)方式

    Java中Byte數(shù)組與InputStream相互轉(zhuǎn)換實(shí)現(xiàn)方式

    在Java中,byte數(shù)組(byte[])和InputStream之間的相互轉(zhuǎn)換是常見(jiàn)的IO操作,下面通過(guò)本文給大家分享Java中Byte數(shù)組與InputStream相互轉(zhuǎn)換方式,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • Javaweb中使用Jdom解析xml的方法

    Javaweb中使用Jdom解析xml的方法

    Jdom是一個(gè)開(kāi)源項(xiàng)目,基于樹(shù)形結(jié)構(gòu),利用純java的技術(shù)對(duì)XML文檔實(shí)現(xiàn)解析,生成,序列化以及多種操作.這篇文章主要介紹了Javaweb中使用Jdom解析xml的方法的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • logback異步輸出日志過(guò)程解讀

    logback異步輸出日志過(guò)程解讀

    文章介紹logback作為SpringBoot默認(rèn)日志框架,通過(guò)異步輸出(AsyncAppender)顯著提升高并發(fā)場(chǎng)景下的程序性能,性能測(cè)試顯示TPS可提高10倍以上,建議生產(chǎn)環(huán)境采用滾動(dòng)文件輸出與異步機(jī)制結(jié)合
    2025-07-07
  • Java current并發(fā)包超詳細(xì)分析

    Java current并發(fā)包超詳細(xì)分析

    current并發(fā)包、在JDK1.5之前Java并沒(méi)有提供線程安全的一些工具類去操作多線程,需要開(kāi)發(fā)人員自行編寫(xiě)實(shí)現(xiàn)線程安全,但仍然無(wú)法完全避免低性能、死鎖、資源管理等問(wèn)題。在JDK1.5時(shí)新增了java.util.current并發(fā)包,其中提供了許多供我們使用的并發(fā)編程工具類
    2023-02-02
  • Java中的collection集合類型總結(jié)

    Java中的collection集合類型總結(jié)

    Java的集合類型都是對(duì)java.util包中Collection接口的繼承,這里我們主要介紹依賴于collection的一些主分支,一起來(lái)看一下Java中的collection集合類型總結(jié)
    2016-05-05

最新評(píng)論

吉林市| 烟台市| 昭觉县| 凉城县| 大荔县| 竹山县| 湛江市| 射阳县| 府谷县| 内江市| 淮滨县| 昌黎县| 辉县市| 南木林县| 北辰区| 柘城县| 开阳县| 绥宁县| 元氏县| 嘉兴市| 洛阳市| 巴里| 中超| 岳西县| 九寨沟县| 翁源县| 苍溪县| 镇平县| 日照市| 松溪县| 乌拉特前旗| 宁陵县| 太仆寺旗| 大丰市| 长子县| 嘉义县| 德钦县| 望城县| 泾源县| 犍为县| 股票|