shutdown和shutdownNow方法的區(qū)別

shutdown和shutdownNow方法的區(qū)別

  • shutdown => 平緩關(guān)閉,等待所有已添加到線程池中的任務(wù)執(zhí)行完在關(guān)閉
  • shutdownNow => 立刻關(guān)閉茸时,停止正在執(zhí)行的任務(wù)盟迟,并返回隊列中未執(zhí)行的任務(wù)

shutdown和shutdownNow方法的優(yōu)缺點

關(guān)閉方法 安全性 響應(yīng)性
shutdown
shutdownNow

通過表格一對比就可以知道shutdown和shutdownNow方法的優(yōu)缺點端姚,shutdown雖然安全设褐,但是響應(yīng)性不高,shutdownNow方法雖然響應(yīng)性高但不安全泡挺,在項目中選擇使用哪種方法關(guān)閉線程池需要進(jìn)行權(quán)衡

如何記錄shutdownNow方法關(guān)閉線程池未完成的任務(wù)

因為shutdownNow方法會立刻停止執(zhí)行中的任務(wù)辈讶,如果不記錄未完成的任務(wù),將會造成任務(wù)的丟失娄猫。使用shutdownNow方法關(guān)閉任務(wù)需要記錄兩部分任務(wù):

  • 隊列中尚未執(zhí)行的任務(wù)
  • 關(guān)閉時正在執(zhí)行的任務(wù)

隊列中尚未執(zhí)行的任務(wù)調(diào)用shutdownNow方法就會返回贱除。記錄關(guān)閉時正在執(zhí)行的任務(wù)需要在execute方法中判斷此時線程池是否關(guān)閉,如果關(guān)閉了將記錄媳溺,實現(xiàn)該功能需要重寫execute方法


Executor和ExecutorService為接口月幌,AbstractExecutorServcie為實現(xiàn)類。在Executor類中有一個execute方法悬蔽,重寫execute方法就是寫一個類繼承AbstractExecutorService
AbstractExecutorService繼承類:TrackingExecutor.java

public class TrackingExecutor extends AbstractExecutorService {
    private static ExecutorService es;

    /**
     * 同步set,存放未完成的任務(wù)
     * */
    private static Set<Runnable> tasksCancelledAtShutdown = Collections.synchronizedSet(new HashSet<>());

    public TrackingExecutor(ExecutorService es) {
        this.es = es;
    }

    public List<Runnable> getCancelledTasks() {
        if (!es.isTerminated()) {
            throw new IllegalStateException();
        }

        return new ArrayList<>(tasksCancelledAtShutdown);
    }

    @Override
    public void execute(Runnable command) {
        es.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    command.run();
                } finally {
                    if (isShutdown() && Thread.currentThread().isInterrupted()) {
                        tasksCancelledAtShutdown.add(command);
                    }
                }
            }
        });
    }


    @Override
    public void shutdown() {
        es.shutdownNow();
    }

    @Override
    public List<Runnable> shutdownNow() {
        return es.shutdownNow();
    }

    @Override
    public boolean isShutdown() {
        return es.isShutdown();
    }

    @Override
    public boolean isTerminated() {
        return es.isTerminated();
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return es.awaitTermination(timeout, unit);
    }
}

說明:

  • 重寫executor方法本質(zhì)就是對提交的Runnable進(jìn)行封裝扯躺,使用try-finally代碼塊在finally中判斷線程池是否被關(guān)閉,線程是否被中斷屯阀,條件成立則將當(dāng)前任務(wù)記錄下來
  • 為什么判斷線程池關(guān)閉以后仍需判斷當(dāng)前線程是否中斷 => 因為shutdownNow方法底層調(diào)用的仍是interrup方法缅帘,如果該任務(wù)是不可中斷的,那么shutdownNow方法對該任務(wù)的關(guān)閉是無效的难衰,該任務(wù)會一直執(zhí)行

TrackingExecutor使用:TrackingExecutorService

public class TrackingExecutorService {
    private  TrackingExecutor trackingExecutor = new TrackingExecutor(Executors.newFixedThreadPool(3));

    private List<Runnable> runnableList;

    public void start() {
        //添加10個任務(wù)
        for (int i = 0; i < 5; i++) {
            trackingExecutor.execute(new Task());
        }
    }

    public void stop() {
        //立刻關(guān)閉線程池
        runnableList = trackingExecutor.shutdownNow();
        try {
            if (trackingExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                for (Runnable runnable : trackingExecutor.getCancelledTasks()) {
                    runnableList.add(runnable);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public List<Runnable> getRunnableList() {
        return runnableList;
    }

    /**
     * 自定義任務(wù)
     * */
    private class Task implements Runnable {
        @Override
        public void run() {
            long start = System.currentTimeMillis();
            while (true) {
                //執(zhí)行一分鐘
                if (System.currentTimeMillis() - start > 1000 * 60) {
                    break;
                }
            }
        }
    }
}

說明:

  • start方法 => 往線程池中提交任務(wù)
  • stop方法 => 關(guān)閉線程池并記錄未完成的任務(wù),未完成的任務(wù)來自兩部分
  • stop方法中awaitTermination方法的使用 => 調(diào)用shutdownNow方法后線程池的停止可能需要一些時間逗栽,因此阻塞等待線程池關(guān)閉盖袭,調(diào)用shutdownNow關(guān)閉線程池成功后該方法將返回true
  • Task類 => 自定義類,強制run方法至少執(zhí)行一分鐘,為了使關(guān)閉線程池時仍有任務(wù)未完成

測試類:Test.java

public class Test {
    public static void main(String[] args) {
        TrackingExecutorService trackingExecutorService = new TrackingExecutorService();
        trackingExecutorService.start();
        trackingExecutorService.stop();
        trackingExecutorService.getRunnableList().stream().forEach(i -> System.out.println("Runnable unfinished: " + i));
    }
}

執(zhí)行結(jié)果:

com.h2t.study.concurrent.TrackingExecutor$1@13969fbe 
com.h2t.study.concurrent.TrackingExecutor$1@6aaa5eb0 

缺點:
記錄的任務(wù)可能已經(jīng)完成了但仍進(jìn)行了記錄鳄虱,因為沒有提供API判斷任務(wù)的執(zhí)行狀態(tài)

最后附:完整代碼

附往期文章:歡迎你的閱讀弟塞、點贊、評論

并發(fā)相關(guān)
1.為什么阿里巴巴要禁用Executors創(chuàng)建線程池拙已?
2.自己的事情自己做决记,線程異常處理

設(shè)計模式相關(guān):
1. 單例模式,你真的寫對了嗎倍踪?
2. (策略模式+工廠模式+map)套餐 Kill 項目中的switch case

JAVA8相關(guān):
1. 使用Stream API優(yōu)化代碼
2. 親系宫,建議你使用LocalDateTime而不是Date哦

數(shù)據(jù)庫相關(guān):
1. mysql數(shù)據(jù)庫時間類型datetime、bigint建车、timestamp的查詢效率比較
2. 很高興扩借!終于踩到了慢查詢的坑

高效相關(guān):
1. 擼一個Java腳手架,一統(tǒng)團(tuán)隊項目結(jié)構(gòu)風(fēng)格

日志相關(guān):
1. 日志框架缤至,選擇Logback Or Log4j2潮罪?
2. Logback配置文件這么寫,TPS提高10倍

工程相關(guān):
1. 閑來無事领斥,動手寫一個LRU本地緩存
2. Redis實現(xiàn)點贊功能模塊
3. JMX可視化監(jiān)控線程池
4. 權(quán)限管理 【SpringSecurity篇】
5. Spring自定義注解從入門到精通
6. java模擬登陸優(yōu)酷
7. QPS這么高嫉到,那就來寫個多級緩存吧
8. java使用phantomjs進(jìn)行截圖

其他:
1. 使用try-with-resources優(yōu)雅關(guān)閉資源
2. 老板,用float存儲金額為什么要扣我工資

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末月洛,一起剝皮案震驚了整個濱河市何恶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌膊存,老刑警劉巖导而,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異隔崎,居然都是意外死亡今艺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門爵卒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來虚缎,“玉大人,你說我怎么就攤上這事钓株∈的担” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵轴合,是天一觀的道長创坞。 經(jīng)常有香客問我,道長受葛,這世上最難降的妖魔是什么题涨? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任偎谁,我火速辦了婚禮,結(jié)果婚禮上纲堵,老公的妹妹穿的比我還像新娘巡雨。我一直安慰自己,他們只是感情好席函,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布铐望。 她就那樣靜靜地躺著,像睡著了一般茂附。 火紅的嫁衣襯著肌膚如雪正蛙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天何之,我揣著相機與錄音跟畅,去河邊找鬼。 笑死溶推,一個胖子當(dāng)著我的面吹牛徊件,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒜危,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼虱痕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辐赞?” 一聲冷哼從身側(cè)響起部翘,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎响委,沒想到半個月后新思,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡赘风,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年夹囚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邀窃。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡荸哟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞬捕,到底是詐尸還是另有隱情鞍历,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布肪虎,位于F島的核電站劣砍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扇救。R本人自食惡果不足惜秆剪,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一赊淑、第九天 我趴在偏房一處隱蔽的房頂上張望爵政。 院中可真熱鬧仅讽,春花似錦、人聲如沸钾挟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掺出。三九已至徽千,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間汤锨,已是汗流浹背双抽。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留闲礼,地道東北人牍汹。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像柬泽,于是被迫代替她去往敵國和親慎菲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容