<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          5種方法,教你判斷線程池是否全部完成

          共 4145字,需瀏覽 9分鐘

           ·

          2022-06-01 06:44

          最近寫小玩具的時候用到了 CountDownLatch 計數(shù)器,然后順便想了想判斷線程池全部結(jié)束有多少種方法。

          在網(wǎng)上搜了下,可能有些沒找到,但是我找到的有(所有方法都是在 ThreadPoolExecutor 線程池方法下測試的):

          • isTerminated() 判斷方式,在執(zhí)行 shutdown() ,關(guān)閉線程池后,判斷是否所有任務(wù)已經(jīng)完成。
          • ThreadPoolExecutorgetCompletedTaskCount() 方法,判斷完成任務(wù)數(shù)和全部任務(wù)數(shù)是否相等。
          • CountDownLatch 計數(shù)器,使用閉鎖計數(shù)來判斷是否全部完成。
          • 手動維護(hù)一個公共計數(shù) ,原理和閉鎖類似,就是更加靈活。
          • 使用 submit 向線程池提交任務(wù),Future 判斷任務(wù)執(zhí)行狀態(tài)。

          好嘞,現(xiàn)在開始一個一個介紹優(yōu)缺點(diǎn)和簡要原理;

          先創(chuàng)建一個 static 線程池,后面好幾個例子就不一一創(chuàng)建了,全部用這個就行了:

          /**
          ?*?創(chuàng)建一個最大線程數(shù)是20的線程池
          ?*/

          public?static?ThreadPoolExecutor?pool?=?new?ThreadPoolExecutor(
          ?????10,?20,?0L,
          ?????TimeUnit.MILLISECONDS,
          ?????new?LinkedBlockingQueue<>());

          然后再準(zhǔn)備一個通用的睡眠方法:

          /**
          ?*?線程執(zhí)行方法,隨機(jī)等待0到10秒
          ?*/

          private?static?void?sleepMtehod(int?index){
          ????try?{
          ????????long?sleepTime?=?new?Double(Math.random()?*?10000).longValue();
          ????????Thread.sleep(sleepTime);
          ????????System.out.println("當(dāng)前線程執(zhí)行結(jié)束:?"?+?index);
          ????}?catch?(InterruptedException?e)?{
          ????????e.printStackTrace();
          ????}
          }

          這個方法就是為了測試的時候區(qū)分線程執(zhí)行完畢的下順序而已。

          好嘞,準(zhǔn)備完畢,現(xiàn)在開始。

          isTerminated 方式

          首先貼上測試代碼:

          private?static?void?shutdownTest()?throws?Exception?{
          ????for?(int?i?=?0;?i?30;?i++)?{
          ????????int?index?=?i;
          ????????pool.execute(()?->?sleepMtehod(index));
          ????}
          ????pool.shutdown();
          ????while?(!pool.isTerminated()){
          ????????Thread.sleep(1000);
          ????????System.out.println("還沒停止。。。");
          ????}
          ????System.out.println("全部執(zhí)行完畢");
          }

          這一種方式就是在主線程中進(jìn)行循環(huán)判斷,全部任務(wù)是否已經(jīng)完成。

          這里有兩個主要方法:

          • shutdown() :啟動有序關(guān)閉,其中先前提交的任務(wù)將被執(zhí)行,但不會接受任何新任務(wù)。如果已經(jīng)關(guān)閉,調(diào)用沒有額外的作用。
          • isTerminated() :如果所有任務(wù)在關(guān)閉后完成,則返回true。請注意, isTerminated 從不是 true,除非 shutdownshutdownNow 先被執(zhí)行。

          通俗點(diǎn)講,就是在執(zhí)行全部任務(wù)后,對線程池進(jìn)行 shutdown() 有序關(guān)閉,然后循環(huán)判斷 isTerminated() ,線程池是否全部完成。

          • 優(yōu)點(diǎn) :操作簡單,代碼更加簡單。
          • 缺點(diǎn) :需要關(guān)閉線程池。一般我在代碼中都是將線程池注入到Spring容器,然后各個組件中統(tǒng)一用同一個,當(dāng)然不能關(guān)閉。

          類似方法擴(kuò)展:

          • shutdownNow() :嘗試停止所有主動執(zhí)行的任務(wù),停止等待任務(wù)的處理,并返回正在等待執(zhí)行的任務(wù)列表。從此方法返回時,這些任務(wù)將從任務(wù)隊列中刪除。通過 Thread.interrupt() 取消任務(wù)。
          • isShutdown() :如果線程池已關(guān)閉,則返回 true 。
          • isTerminating() :如果在 shutdown()shutdownNow() 之后終止 ,但尚未完全終止,則返回true。
          • waitTermination(long timeout, TimeUnit unit) :當(dāng)前線程阻塞,直到等所有已提交的任務(wù)(包括正在跑的和隊列中等待的)執(zhí)行完,或者等超時時間到,或者線程被中斷拋出異常;全部執(zhí)行完返回true,超時返回false。也可以用這個方法代替 isTerminated() 進(jìn)行判斷 。

          getCompletedTaskCount

          還是一樣,貼上代碼:

          private?static?void?taskCountTest()?throws?Exception?{
          ????????for?(int?i?=?0;?i?30;?i++)?{
          ????????????int?index?=?i;
          ????????????pool.execute(()?->?sleepMtehod(index));
          ????????}
          ????????//當(dāng)線程池完成的線程數(shù)等于線程池中的總線程數(shù)
          ????????while?(!(pool.getTaskCount()?==?pool.getCompletedTaskCount()))?{
          ????????????System.out.println("任務(wù)總數(shù):"?+?pool.getTaskCount()?+?";?已經(jīng)完成任務(wù)數(shù):"?+?pool.getCompletedTaskCount());
          ????????????Thread.sleep(1000);
          ????????????System.out.println("還沒停止。。。");
          ????????}
          ????????System.out.println("全部執(zhí)行完畢");
          ????}

          還是一樣在主線程循環(huán)判斷,主要就兩個方法:

          • getTaskCount() :返回計劃執(zhí)行的任務(wù)總數(shù)。由于任務(wù)和線程的狀態(tài)可能在計算過程中動態(tài)變化,因此返回的值只是一個近似值。
          • getCompletedTaskCount() :返回完成執(zhí)行的任務(wù)的大致總數(shù)。因?yàn)槿蝿?wù)和線程的狀態(tài)可能在計算過程中動態(tài)地改變,所以返回的值只是一個近似值,但是在連續(xù)的調(diào)用中并不會減少。

          這個好理解,總?cè)蝿?wù)數(shù)等于已完成任務(wù)數(shù),就表示全部執(zhí)行完畢。

          • 優(yōu)點(diǎn) :完全使用了 ThreadPoolExecutor 提供的方法,并且不必關(guān)閉線程池,避免了創(chuàng)建和銷毀帶來的損耗。
          • 缺點(diǎn) :上面的解釋也看到了,使用這種判斷存在很大的限制條件;必須確定,在循環(huán)判斷過程中,沒有新的任務(wù)產(chǎn)生。差不多意思就是,這個線程池只能在這條線程中使用。

          其他 :

          最后扯兩句,因?yàn)槲矣肕ain方法行的,跑完后 main 沒有結(jié)束,是因?yàn)榉鞘刈o(hù)線程如果不終止,程序是不會結(jié)束的。而線程池 Worker 線程里寫了一個死循環(huán),而且被設(shè)置成了非守護(hù)線程。

          CountDownLatch 計數(shù)器

          這種方法是我比較常用的方法,先看代碼:

          private?static?void?countDownLatchTest()?throws?Exception?{
          ?????//計數(shù)器,判斷線程是否執(zhí)行結(jié)束
          ?????CountDownLatch?taskLatch?=?new?CountDownLatch(30);
          ?????for?(int?i?=?0;?i?30;?i++)?{
          ?????????int?index?=?i;
          ?????????pool.execute(()?->?{
          ?????????????sleepMtehod(index);
          ?????????????taskLatch.countDown();
          ?????????????System.out.println("當(dāng)前計數(shù)器數(shù)量:"?+?taskLatch.getCount());
          ?????????});
          ?????}
          ?????//當(dāng)前線程阻塞,等待計數(shù)器置為0
          ?????taskLatch.await();
          ?????System.out.println("全部執(zhí)行完畢");
          ?}

          這種方法,呃,應(yīng)該是看起來比較高級的,我也不知道別的大佬怎么寫的,反正我就用這個。

          這個方法需要介紹下這個工具類 CountDownLatch 。先把這種方式的優(yōu)缺點(diǎn)寫了,后面再詳細(xì)介紹這個類。

          • 優(yōu)點(diǎn) :代碼優(yōu)雅,不需要對線程池進(jìn)行操作,將線程池作為 Bean 的情況下有很好的使用場景。
          • 缺點(diǎn) :需要提前知道線程數(shù)量;性能確實(shí),呃呃呃呃呃,差了點(diǎn)。哦對了,還需要在線程代碼塊內(nèi)加上異常判斷,否則在 countDown 之前發(fā)生異常而沒有處理,就會導(dǎo)致主線程永遠(yuǎn)阻塞在 await。

          CountDownLatch 概述

          CountDownLatch 是 JDK 提供的一個同步工具,它可以讓一個或多個線程等待,一直等到其他線程中執(zhí)行完成一組操作。

          常用的方法有 countDown 方法和 await 方法,CountDownLatch 在初始化時,需要指定用給定一個整數(shù)作為計數(shù)器。

          當(dāng)調(diào)用 countDown 方法時,計數(shù)器會被減1;當(dāng)調(diào)用 await 方法時,如果計數(shù)器大于0時,線程會被阻塞,一直到計數(shù)器被 countDown 方法減到0時,線程才會繼續(xù)執(zhí)行。

          計數(shù)器是無法重置的,當(dāng)計數(shù)器被減到0時,調(diào)用 await 方法都會直接返回。

          維護(hù)一個公共計數(shù)

          這種方式其實(shí)和 CountDownLatch 原理類似。

          先維護(hù)一個靜態(tài)變量

          private?static?int?taskNum?=?0;

          然后在線程任務(wù)結(jié)束時,進(jìn)行靜態(tài)變量操作:

          private?static?void?staticCountTest()?throws?Exception?{
          ?????Lock?lock?=?new?ReentrantLock();
          ?????for?(int?i?=?0;?i?30;?i++)?{
          ?????????int?index?=?i;
          ?????????pool.execute(()?->?{
          ?????????????sleepMtehod(index);
          ?????????????lock.lock();
          ?????????????taskNum++;
          ?????????????lock.unlock();
          ?????????});
          ?????}
          ?????while(taskNum?30)?{
          ?????????Thread.sleep(1000);
          ?????????System.out.println("還沒停止。。。當(dāng)前完成任務(wù)數(shù):"?+?taskNum);
          ?????}
          ?????System.out.println("全部執(zhí)行完畢");
          ?}

          其實(shí)就是加鎖計數(shù),循環(huán)判斷。

          • 優(yōu)點(diǎn) :手動維護(hù)方式更加靈活,對于一些特殊場景可以手動處理。
          • 缺點(diǎn) :和 CountDownLatch 相比,一樣需要知道線程數(shù)目,但是代碼實(shí)現(xiàn)比較麻煩,相對于靈活這一個優(yōu)勢,貌似投入產(chǎn)出并不對等。

          Future 判斷任務(wù)執(zhí)行狀態(tài)

          Future 是用來裝載線程結(jié)果的,不過,用這個來進(jìn)行判斷寫代碼總感覺怪怪的。

          因?yàn)?Future 只能裝載一條線程的返回結(jié)果,多條線程總不能用 List 在接收 Future 。

          這里就開一個線程做個演示:

          private?static?void?futureTest()?throws?Exception?{
          ????Future?future?=?pool.submit(()?->?sleepMtehod(1));
          ????while?(!future.isDone()){
          ????????Thread.sleep(500);
          ????????System.out.println("還沒停止。。。");
          ????}
          ????System.out.println("全部執(zhí)行完畢");
          }

          這種方式就不寫優(yōu)缺點(diǎn)了,因?yàn)?Future 的主要使用場景并不是用于判斷任務(wù)執(zhí)行狀態(tài)。

          來源:https://blog.csdn.net/m0_46144826


          如有文章對你有幫助,

          在看”和轉(zhuǎn)發(fā)是對我最大的支持!

          推薦

          點(diǎn)擊領(lǐng)取:151個大廠面試講解!(圖片可上下滑動!)??


          瀏覽 22
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久久久久91香蕉国产 | 欧美三级精品网站 | 在线免费观看成人网站 | 日韩在线免费 | 五月丁香俺也去国产 |