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

Java中如何正確的停掉線程

 更新時(shí)間:2025年08月21日 11:23:30   作者:程序員小假  
Java通過interrupt()通知線程停止而非強(qiáng)制,確保線程自主處理中斷,避免數(shù)據(jù)損壞,線程池的shutdown()等待任務(wù)完成,shutdownNow()強(qiáng)制中斷并返回未執(zhí)行任務(wù),二者實(shí)現(xiàn)有序關(guān)閉,本文給大家介紹Java中如何正確的停掉線程,感興趣的朋友一起看看吧

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

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

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

事實(shí)上,Java 希望程序間能夠相互通知、相互協(xié)作地管理線程,因?yàn)槿绻涣私鈱Ψ秸谧龅墓ぷ鳎Q(mào)然強(qiáng)制停止線程就可能會造成一些安全的問題。
比如:
線程正在寫入一個(gè)文件,這時(shí)收到終止信號,它就需要根據(jù)自身業(yè)務(wù)判斷,是選擇立即停止,還是將整個(gè)文件寫入成功后停止。如果選擇立即停止就可能造成數(shù)據(jù)不完整,不管是中斷命令發(fā)起者,還是接收者都不希望數(shù)據(jù)出現(xiàn)問題。

如何用interrupt停止線程

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

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

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)容很簡單,就是打印 0~999 的數(shù)字,每打印一個(gè)數(shù)字 count 值加 1,可以看到,線程會在每次循環(huán)開始之前,檢查是否被中斷了。接下來在 main 函數(shù)中會啟動該線程,然后休眠 5 毫秒后立刻中斷線程,該線程會檢測到中斷信號,于是在還沒打印完1000個(gè)數(shù)的時(shí)候就會停下來,這種就屬于通過 interrupt 正確停止線程的情況。

sleep 期間能否感受到中斷

先說結(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é)果猜這么著,程序會拋出異常

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

    合理利用好 try/catch

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

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

    停止線程的方式有幾種

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

    下面就對這些方法逐一展開。 

    shutdown()

    調(diào)用 shutdown() 方法之后線程池并不是立刻就被關(guān)閉,因?yàn)檫@時(shí)線程池中可能還有很多任務(wù)正在被執(zhí)行,或是任務(wù)隊(duì)列中有大量正在等待被執(zhí)行的任務(wù),調(diào)用 shutdown() 方法后線程池會在執(zhí)行完正在執(zhí)行的任務(wù)和隊(duì)列中等待的任務(wù)后才徹底關(guān)閉。
    但這并不代表 shutdown() 操作是沒有任何效果的,調(diào)用 shutdown() 方法后如果還有新的任務(wù)被提交,線程池則會根據(jù)拒絕策略直接拒絕后續(xù)新提交的任務(wù)。 

    isShutdown()

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

    isTerminated()

    這個(gè)方法可以檢測線程池是否真正“終結(jié)”了,這不僅代表線程池已關(guān)閉,同時(shí)代表線程池中的所有任務(wù)都已經(jīng)都執(zhí)行完畢了,因?yàn)閯偛耪f過,調(diào)用 shutdown 方法之后,線程池會繼續(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í)行,線程池并沒有真正“終結(jié)”。直到所有任務(wù)都執(zhí)行完畢了,調(diào)用 isTerminated() 方法才會返回 true,這表示線程池已關(guān)閉并且線程池內(nèi)部是空的,所有剩余的任務(wù)都執(zhí)行完畢了。 

    awaitTermination()

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

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

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

    shutdownNow()

    最后一個(gè)方法是 shutdownNow(),也是 5 種方法里功能最強(qiáng)大的,它與第一種 shutdown 方法不同之處在于名字中多了一個(gè)單詞 Now,也就是表示立刻關(guān)閉的意思。
    在執(zhí)行 shutdownNow 方法之后,首先會給所有線程池中的線程發(fā)送 interrupt 中斷信號,嘗試中斷這些任務(wù)的執(zhí)行,然后會將任務(wù)隊(duì)列中正在等待的所有任務(wù)轉(zhuǎn)移到一個(gè) List 中并返回,可以根據(jù)返回的任務(wù) List 來進(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() 代碼,這行代碼會讓每一個(gè)已經(jīng)啟動的線程都中斷,這樣線程就可以在執(zhí)行任務(wù)期間檢測到中斷信號并進(jìn)行相應(yīng)的處理,提前結(jié)束任務(wù)。
    這里需要注意的是,由于 Java 中不推薦強(qiáng)行停止線程的機(jī)制的限制,即便調(diào)用了 shutdownNow 方法,如果被中斷的線程對于中斷信號不理不睬,那么依然有可能導(dǎo)致任務(wù)不會停止。 

    總結(jié)

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

    到此這篇關(guān)于Java中如何正確的停掉線程的文章就介紹到這了,更多相關(guān)java停掉線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

    相關(guān)文章

    • Spring中的Aware接口及應(yīng)用場景詳解

      Spring中的Aware接口及應(yīng)用場景詳解

      這篇文章主要介紹了Spring中的Aware接口及應(yīng)用場景,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
      2024-01-01
    • 基于spring注入為null的原因及解決方案

      基于spring注入為null的原因及解決方案

      這篇文章主要介紹了spring注入為null的原因及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
      2021-08-08
    • springboot定時(shí)任務(wù)不起作用問題及解決

      springboot定時(shí)任務(wù)不起作用問題及解決

      文章主要介紹了Spring Boot中延遲加載bean的概念,并討論了如何解決定時(shí)任務(wù)不執(zhí)行的問題,通過設(shè)置`@Lazy(false)`注解,可以指定某些類不使用延遲加載,從而解決定時(shí)任務(wù)無法執(zhí)行的問題
      2024-11-11
    • java使用httpclient模擬post請求和get請求示例

      java使用httpclient模擬post請求和get請求示例

      這篇文章主要介紹了java使用httpclient模擬post請求和get請求示例,需要的朋友可以參考下
      2014-02-02
    • Netty核心功能之?dāng)?shù)據(jù)容器ByteBuf詳解

      Netty核心功能之?dāng)?shù)據(jù)容器ByteBuf詳解

      這篇文章主要為大家介紹了Netty核心功能之?dāng)?shù)據(jù)容器ByteBuf詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
      2022-10-10
    • druid連接池的參數(shù)配置示例全面解析

      druid連接池的參數(shù)配置示例全面解析

      這篇文章主要為大家介紹了druid連接池的參數(shù)配置示例全面解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
      2023-09-09
    • Activiti explorer.war示例工程使用過程圖解

      Activiti explorer.war示例工程使用過程圖解

      這篇文章主要介紹了Activiti explorer.war示例工程使用過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
      2020-03-03
    • Java調(diào)用shell命令涉及管道、重定向時(shí)不生效問題及解決

      Java調(diào)用shell命令涉及管道、重定向時(shí)不生效問題及解決

      這篇文章主要介紹了Java調(diào)用shell命令涉及管道、重定向時(shí)不生效問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
      2022-12-12
    • jstack配合top命令分析CPU飆高、程序死鎖問題

      jstack配合top命令分析CPU飆高、程序死鎖問題

      記得前段時(shí)間,同事說他們測試環(huán)境的服務(wù)器cpu使用率一直處于100%,本地又沒有什么接口調(diào)用,為什么會這樣?cpu使用率居高不下,自然是有某些線程一直占用著cpu資源,那又如何查看占用cpu較高的線程
      2021-09-09
    • springmvc組件中的HandlerMapping解析

      springmvc組件中的HandlerMapping解析

      這篇文章主要介紹了springmvc九大組件中的HandlerMapping解析,HandlerMapping表示的是一個(gè)URL與一個(gè)Handler(可以簡單的理解為Controller中有@RequestMapping注解的方法)之間的映射關(guān)系,需要的朋友可以參考下
      2023-09-09

    最新評論

    仙游县| 定南县| 黔南| 昌宁县| 民乐县| 永昌县| 龙胜| 临颍县| 怀化市| 西峡县| 栖霞市| 二连浩特市| 南昌市| 女性| 远安县| 闽清县| 巫山县| 拉萨市| 华容县| 东丽区| 通州市| 阳朔县| 正蓝旗| 威宁| 循化| 海林市| 甘孜| 青铜峡市| 太仓市| 彩票| 封开县| 迭部县| 车险| 格尔木市| 夹江县| 彝良县| 定安县| 图们市| 白城市| 罗定市| 建湖县|