線程池的使用

回顧線程的基本知識(shí)

我們最常見的創(chuàng)建線程的幾種方法:一是繼承Thread類,二是實(shí)現(xiàn)Runnable的接口,三是實(shí)現(xiàn)Callable接口。單個(gè)線程的創(chuàng)建和銷毀會(huì)消耗機(jī)器資源,如果線程數(shù)量多的話,頻繁的創(chuàng)建和銷毀會(huì)大大的降低程序運(yùn)行的效率,耗費(fèi)大量的內(nèi)存,因?yàn)檎碚f線程執(zhí)行完畢后死亡,會(huì)被當(dāng)作垃圾回收。怎么能讓線程復(fù)用、統(tǒng)一管理命名線程、提高資源的使用率?線程池就能完美的解決這個(gè)問題。

為什么使用線程池

線程池是一種多線程處理形式,處理過程中將任務(wù)添加到隊(duì)列,線程池在工程啟動(dòng)時(shí)并不會(huì)立即創(chuàng)建大量空閑的線程,程序?qū)⒁粋€(gè)任務(wù)傳給線程池,線程池就會(huì)啟動(dòng)一條線程來執(zhí)行這個(gè)任務(wù)。執(zhí)行結(jié)束以后,該線程并不會(huì)死亡,而是再次返回線程池中成為空閑狀態(tài),等待執(zhí)行下一個(gè)任務(wù)。
簡而言之,線程池就是一組線程的集合。

線程池實(shí)現(xiàn)原理

SpringBoot配置線程池

首先在啟動(dòng)類中配置如下Bean

   @Bean("defaultThreadPool")
   public ThreadPoolExecutor defaultThreadPool() {
        log.info("start asyncServiceExecutor");

        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("HiveMetric-pool-%d").build();

        //  核心線程數(shù)
        int corePoolSize = 10;

        //  配置最大線程數(shù)
        int maximumPoolSize = 20;

        //  當(dāng)線程數(shù)大于內(nèi)核數(shù)時(shí),這是多余的空閑線程將在終止之前等待新任務(wù)的最長時(shí)間
        long keepAliveTime = 2L;

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024), threadFactory, new ThreadPoolExecutor.AbortPolicy());
        log.info("線程池,{}", threadPoolExecutor);

        return threadPoolExecutor;
    }

1)首先創(chuàng)建一個(gè)ThreadFactoryBuilder給線程統(tǒng)一命名,方便管理及檢索日志;
2)通過ThreadPoolExecutor來創(chuàng)建一個(gè)線程池,該類來自于JUC包下,下面介紹一下重要的幾個(gè)參數(shù);
corePoolSize:核心線程數(shù)量
maximumPoolSize:線程池中的線程總數(shù)=核心線程數(shù)+非核心線程數(shù)
keepAliveTime:當(dāng)線程數(shù)大于內(nèi)核數(shù)時(shí),多余的空閑線程將在終止之前等待新任務(wù)的最長時(shí)間。
TimeUnit:時(shí)間單位
BlockingQueue<Runnable>:在執(zhí)行任務(wù)之前用于保留任務(wù)的隊(duì)列。
ThreadFactory:線程工廠
RejectedExecutionHandler:因?yàn)檫_(dá)到了線程界限和隊(duì)列容量而在執(zhí)行被阻止時(shí)使用的處理器。線程池中的線程已經(jīng)用完了,無法繼續(xù)為新任務(wù)服務(wù),同時(shí),等待隊(duì)列也已經(jīng)排滿了,再也塞不下新任務(wù)了。這時(shí)候我們就需要拒絕策略機(jī)制合理的處理這個(gè)問題。JDK 內(nèi)置的拒絕策略如下:

  • AbortPolicy : 直接拋出異常,阻止系統(tǒng)正常運(yùn)行。
  • CallerRunsPolicy : 只要線程池未關(guān)閉,該策略直接在調(diào)用者線程中,運(yùn)行當(dāng)前被丟棄的
    任務(wù)。顯然這樣做不會(huì)真的丟棄任務(wù),但是,任務(wù)提交線程的性能極有可能會(huì)急劇下降。
  • DiscardOldestPolicy : 丟棄最老的一個(gè)請求,也就是即將被執(zhí)行的一個(gè)任務(wù),并嘗試再
    次提交當(dāng)前任務(wù)。
  • DiscardPolicy : 該策略默默地丟棄無法處理的任務(wù),不予任何處理。如果允許任務(wù)丟
    失,這是最好的一種方案。
    以上內(nèi)置拒絕策略均實(shí)現(xiàn)了 RejectedExecutionHandler 接口,若以上策略仍無法滿足實(shí)際需要,完全可以自己擴(kuò)展RejectedExecutionHandler 接口。
    3)在service層通過如下方法注入
    @Autowired
    private ThreadPoolExecutor defaultThreadPool;

ThreadPoolExecutor繼承自AbstractExecutorService,下面看一下submit()。

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

最后通過Future<V>get()的方法取出線程的執(zhí)行結(jié)果。

        for (HostEntity hostEntity : hiveServer2Info) {
            String hostName = hostEntity.getHostName();
            Future<JSONObject> submit = defaultThreadPool.submit(() -> stringConvertJsonObject(hostName, getJmxFileContent(hostName, metricFileLocation)));
            map.put(hostName, submit);
        }

        for (Map.Entry<String, Future<JSONObject>> next : map.entrySet()) {
            String hostName = next.getKey();
            try {
                result.put(hostName, next.getValue().get());
            } catch (Exception e) {
                log.error("線程池獲取返回結(jié)果異常!主機(jī)名:{}", hostName, e);
            }
        }

之前從多臺(tái)服務(wù)器解析文件由串行改為線程池并行的解決方法,初步優(yōu)化之后線上接口的響應(yīng)時(shí)間由10s+降為1s。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容