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

java線(xiàn)程池ThreadPoolExecutor的八種拒絕策略示例詳解

 更新時(shí)間:2022年02月18日 16:41:06   作者:廈門(mén)在乎科技  
ThreadPoolExecutor是一個(gè)典型的緩存池化設(shè)計(jì)的產(chǎn)物,因?yàn)槌刈佑写笮?當(dāng)池子體積不夠承載時(shí),就涉及到拒絕策略。JDK中已預(yù)設(shè)了?4?種線(xiàn)程池拒絕策略,下面結(jié)合場(chǎng)景詳細(xì)聊聊這些策略的使用場(chǎng)景以及還能擴(kuò)展哪些拒絕策略

談到 Java 的線(xiàn)程池最熟悉的莫過(guò)于 ExecutorService 接口了,jdk1.5 新增的 java.util.concurrent 包下的這個(gè) api,大大的簡(jiǎn)化了多線(xiàn)程代碼的開(kāi)發(fā)。而不論你用 FixedThreadPool 還是 CachedThreadPool 其背后實(shí)現(xiàn)都是ThreadPoolExecutor。

池化設(shè)計(jì)思想

池話(huà)設(shè)計(jì)應(yīng)該不是一個(gè)新名詞。我們常見(jiàn)的如 Java 線(xiàn)程池、JDBC 連接池、Redis 連接池等就是這類(lèi)設(shè)計(jì)的代表實(shí)現(xiàn)。這種設(shè)計(jì)會(huì)初始預(yù)設(shè)資源,解決的問(wèn)題就是抵消每次獲取資源的消耗,如創(chuàng)建線(xiàn)程的開(kāi)銷(xiāo),獲取遠(yuǎn)程連接的開(kāi)銷(xiāo)等。

就好比你去食堂打飯,打飯的大媽會(huì)先把飯盛好幾份放那里,你來(lái)了就直接拿著飯盒加菜即可,不用再臨時(shí)又盛飯又打菜,效率就高了。

除了初始化資源,池化設(shè)計(jì)還包括如下這些特征:池子的初始值、池子的活躍值、池子的最大值等,這些特征可以直接映射到 Java 線(xiàn)程池和數(shù)據(jù)庫(kù)連接池的成員屬性中。

線(xiàn)程池觸發(fā)拒絕策略的時(shí)機(jī)

和數(shù)據(jù)源連接池不一樣,線(xiàn)程池除了初始大小和池子最大值,還多了一個(gè)阻塞隊(duì)列來(lái)緩沖。數(shù)據(jù)源連接池一般請(qǐng)求的連接數(shù)超過(guò)連接池的最大值的時(shí)候就會(huì)觸發(fā)拒絕策略,策略一般是阻塞等待設(shè)置的時(shí)間或者直接拋異常。

想要了解線(xiàn)程池什么時(shí)候觸發(fā)拒絕粗略,需要明確上面三個(gè)參數(shù)的具體含義,是這三個(gè)參數(shù)總體協(xié)調(diào)的結(jié)果,而不是簡(jiǎn)單的超過(guò)最大線(xiàn)程數(shù)就會(huì)觸發(fā)線(xiàn)程拒絕粗略,當(dāng)提交的任務(wù)數(shù)大于 corePoolSize 時(shí),會(huì)優(yōu)先放到隊(duì)列緩沖區(qū),只有填滿(mǎn)了緩沖區(qū)后,才會(huì)判斷當(dāng)前運(yùn)行的任務(wù)是否大于 maxPoolSize,小于時(shí)會(huì)新建線(xiàn)程處理。大于時(shí)就觸發(fā)了拒絕策略,總結(jié)就是:當(dāng)前提交任務(wù)數(shù)大于(maxPoolSize + queueCapacity)時(shí)就會(huì)觸發(fā)線(xiàn)程池的拒絕策略了。

JDK內(nèi)置4種線(xiàn)程池拒絕策略

拒絕策略接口定義

在分析 JDK 自帶的線(xiàn)程池拒絕策略前,先看下 JDK 定義的 拒絕策略接口,如下:

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

接口定義很明確,當(dāng)觸發(fā)拒絕策略時(shí),線(xiàn)程池會(huì)調(diào)用你設(shè)置的具體的策略,將當(dāng)前提交的任務(wù)以及線(xiàn)程池實(shí)例本身傳遞給你處理,具體作何處理,不同場(chǎng)景會(huì)有不同的考慮,下面看 JDK 為我們內(nèi)置了哪些實(shí)現(xiàn):

CallerRunsPolicy(調(diào)用者運(yùn)行策略)

   public static class CallerRunsPolicy implements RejectedExecutionHandler {
         public CallerRunsPolicy() { }
          public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
             if (!e.isShutdown()) {
               r.run();
             }
         }
   }

功能:當(dāng)觸發(fā)拒絕策略時(shí),只要線(xiàn)程池沒(méi)有關(guān)閉,就由提交任務(wù)的當(dāng)前線(xiàn)程處理。

使用場(chǎng)景:一般在不允許失敗的、對(duì)性能要求不高、并發(fā)量較小的場(chǎng)景下使用,因?yàn)榫€(xiàn)程池一般情況下不會(huì)關(guān)閉,也就是提交的任務(wù)一定會(huì)被運(yùn)行,但是由于是調(diào)用者線(xiàn)程自己執(zhí)行的,當(dāng)多次提交任務(wù)時(shí),就會(huì)阻塞后續(xù)任務(wù)執(zhí)行,性能和效率自然就慢了。

AbortPolicy(中止策略)

     public static class AbortPolicy implements RejectedExecutionHandler { 
         public AbortPolicy() { }
         public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
             throw new RejectedExecutionException("Task " + r.toString() +
                                                  " rejected from " +
                                                  e.toString());
         }
    }

功能:當(dāng)觸發(fā)拒絕策略時(shí),直接拋出拒絕執(zhí)行的異常,中止策略的意思也就是打斷當(dāng)前執(zhí)行流程

使用場(chǎng)景:這個(gè)就沒(méi)有特殊的場(chǎng)景了,但是一點(diǎn)要正確處理拋出的異常。ThreadPoolExecutor 中默認(rèn)的策略就是AbortPolicy,ExecutorService 接口的系列 ThreadPoolExecutor 因?yàn)槎紱](méi)有顯示的設(shè)置拒絕策略,所以默認(rèn)的都是這個(gè)。但是請(qǐng)注意,ExecutorService 中的線(xiàn)程池實(shí)例隊(duì)列都是無(wú)界的,也就是說(shuō)把內(nèi)存撐爆了都不會(huì)觸發(fā)拒絕策略。當(dāng)自己自定義線(xiàn)程池實(shí)例時(shí),使用這個(gè)策略一定要處理好觸發(fā)策略時(shí)拋的異常,因?yàn)樗麜?huì)打斷當(dāng)前的執(zhí)行流程。

DiscardPolicy(丟棄策略)

    public static class DiscardPolicy implements RejectedExecutionHandler {
        public DiscardPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

功能:直接靜悄悄的丟棄這個(gè)任務(wù),不觸發(fā)任何動(dòng)作

使用場(chǎng)景:如果你提交的任務(wù)無(wú)關(guān)緊要,你就可以使用它 。因?yàn)樗褪莻€(gè)空實(shí)現(xiàn),會(huì)悄無(wú)聲息的吞噬你的的任務(wù)。所以這個(gè)策略基本上不用了

DiscardOldestPolicy(棄老策略)

     public static class DiscardOldestPolicy implements RejectedExecutionHandler {
         public DiscardOldestPolicy() { } 
         public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
             if (!e.isShutdown()) {
                 e.getQueue().poll();
                 e.execute(r);
             }
        }
    }

功能:如果線(xiàn)程池未關(guān)閉,就彈出隊(duì)列頭部的元素,然后嘗試執(zhí)行

使用場(chǎng)景:這個(gè)策略還是會(huì)丟棄任務(wù),丟棄時(shí)也是毫無(wú)聲息,但是特點(diǎn)是丟棄的是老的未執(zhí)行的任務(wù),而且是待執(zhí)行優(yōu)先級(jí)較高的任務(wù)?;谶@個(gè)特性,我能想到的場(chǎng)景就是,發(fā)布消息,和修改消息,當(dāng)消息發(fā)布出去后,還未執(zhí)行,此時(shí)更新的消息又來(lái)了,這個(gè)時(shí)候未執(zhí)行的消息的版本比現(xiàn)在提交的消息版本要低就可以被丟棄了。因?yàn)殛?duì)列中還有可能存在消息版本更低的消息會(huì)排隊(duì)執(zhí)行,所以在真正處理消息的時(shí)候一定要做好消息的版本比較。

第三方實(shí)現(xiàn)的拒絕策略

Dubbo 中的線(xiàn)程拒絕策略

 public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
      protected static final Logger logger = LoggerFactory.getLogger(AbortPolicyWithReport.class);
      private final String threadName;
      private final URL url;
      private static volatile long lastPrintTime = 0;
    private static Semaphore guard = new Semaphore(1);
    public AbortPolicyWithReport(String threadName, URL url) {
        this.threadName = threadName;
        this.url = url;
    }
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        String msg = String.format("Thread pool is EXHAUSTED!" +
                        " Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: %d)," +
                        " Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s), in %s://%s:%d!",
                threadName, e.getPoolSize(), e.getActiveCount(), e.getCorePoolSize(), e.getMaximumPoolSize(), e.getLargestPoolSize(),
                e.getTaskCount(), e.getCompletedTaskCount(), e.isShutdown(), e.isTerminated(), e.isTerminating(),
                url.getProtocol(), url.getIp(), url.getPort());
        logger.warn(msg);
        dumpJStack();
        throw new RejectedExecutionException(msg);
    }
    private void dumpJStack() {
       //省略實(shí)現(xiàn)
    }
}

可以看到,當(dāng)dubbo的工作線(xiàn)程觸發(fā)了線(xiàn)程拒絕后,主要做了三個(gè)事情,原則就是盡量讓使用者清楚觸發(fā)線(xiàn)程拒絕策略的真實(shí)原因

  • 輸出了一條警告級(jí)別的日志,日志內(nèi)容為線(xiàn)程池的詳細(xì)設(shè)置參數(shù),以及線(xiàn)程池當(dāng)前的狀態(tài),還有當(dāng)前拒絕任務(wù)的一些詳細(xì)信息??梢哉f(shuō),這條日志,使用dubbo的有過(guò)生產(chǎn)運(yùn)維經(jīng)驗(yàn)的或多或少是見(jiàn)過(guò)的,這個(gè)日志簡(jiǎn)直就是日志打印的典范,其他的日志打印的典范還有spring。得益于這么詳細(xì)的日志,可以很容易定位到問(wèn)題所在
  • 輸出當(dāng)前線(xiàn)程堆棧詳情,這個(gè)太有用了,當(dāng)你通過(guò)上面的日志信息還不能定位問(wèn)題時(shí),案發(fā)現(xiàn)場(chǎng)的dump線(xiàn)程上下文信息就是你發(fā)現(xiàn)問(wèn)題的救命稻草,這個(gè)可以參考《dubbo線(xiàn)程池耗盡事件-"CyclicBarrier惹的禍"》
  • 繼續(xù)拋出拒絕執(zhí)行異常,使本次任務(wù)失敗,這個(gè)繼承了JDK默認(rèn)拒絕策略的特性

Netty 中的線(xiàn)程池拒絕策略

     private static final class NewThreadRunsPolicy implements RejectedExecutionHandler {
         NewThreadRunsPolicy() {
             super();
         }
          public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
             try {
                 final Thread t = new Thread(r, "Temporary task executor");
                 t.start();
            } catch (Throwable e) {
                throw new RejectedExecutionException(
                        "Failed to start a new thread", e);
            }
        }
    }

Netty 中的實(shí)現(xiàn)很像 JDK 中的 CallerRunsPolicy,舍不得丟棄任務(wù)。不同的是,CallerRunsPolicy 是直接在調(diào)用者線(xiàn)程執(zhí)行的任務(wù)。而 Netty是新建了一個(gè)線(xiàn)程來(lái)處理的。所以,Netty的實(shí)現(xiàn)相較于調(diào)用者執(zhí)行策略的使用面就可以擴(kuò)展到支持高效率高性能的場(chǎng)景了。但是也要注意一點(diǎn),Netty的實(shí)現(xiàn)里,在創(chuàng)建線(xiàn)程時(shí)未做任何的判斷約束,也就是說(shuō)只要系統(tǒng)還有資源就會(huì)創(chuàng)建新的線(xiàn)程來(lái)處理,直到new不出新的線(xiàn)程了,才會(huì)拋創(chuàng)建線(xiàn)程失敗的異常

ActiveMQ 中的線(xiàn)程池拒絕策略

  new RejectedExecutionHandler() {
                 @Override
                 public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
                     try {
                         executor.getQueue().offer(r, 60, TimeUnit.SECONDS);
                     } catch (InterruptedException e) {
                         throw new RejectedExecutionException("Interrupted waiting for BrokerService.worker");
                     }
                     throw new RejectedExecutionException("Timed Out while attempting to enqueue Task.");
                }
            });

activeMq中的策略屬于最大努力執(zhí)行任務(wù)型,當(dāng)觸發(fā)拒絕策略時(shí),在嘗試一分鐘的時(shí)間重新將任務(wù)塞進(jìn)任務(wù)隊(duì)列,當(dāng)一分鐘超時(shí)還沒(méi)成功時(shí),就拋出異常

PinPoint 中的線(xiàn)程池拒絕策略

 public class RejectedExecutionHandlerChain implements RejectedExecutionHandler {
     private final RejectedExecutionHandler[] handlerChain;
     public static RejectedExecutionHandler build(List<RejectedExecutionHandler> chain) {
         Objects.requireNonNull(chain, "handlerChain must not be null");
         RejectedExecutionHandler[] handlerChain = chain.toArray(new RejectedExecutionHandler[0]);
         return new RejectedExecutionHandlerChain(handlerChain);
     }
     private RejectedExecutionHandlerChain(RejectedExecutionHandler[] handlerChain) {
        this.handlerChain = Objects.requireNonNull(handlerChain, "handlerChain must not be null");
    }
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        for (RejectedExecutionHandler rejectedExecutionHandler : handlerChain) {
            rejectedExecutionHandler.rejectedExecution(r, executor);
        }
    }
}

pinpoint的拒絕策略實(shí)現(xiàn)很有特點(diǎn),和其他的實(shí)現(xiàn)都不同。他定義了一個(gè)拒絕策略鏈,包裝了一個(gè)拒絕策略列表,當(dāng)觸發(fā)拒絕策略時(shí),會(huì)將策略鏈中的rejectedExecution依次執(zhí)行一遍。

小結(jié)

前文從線(xiàn)程池設(shè)計(jì)思想,以及線(xiàn)程池觸發(fā)拒絕策略的時(shí)機(jī)引出java線(xiàn)程池拒絕策略接口的定義。并輔以JDK內(nèi)置4種以及四個(gè)第三方開(kāi)源軟件的拒絕策略定義描述了線(xiàn)程池拒絕策略實(shí)現(xiàn)的各種思路和使用場(chǎng)景。希望閱讀此文后能讓你對(duì)java線(xiàn)程池拒絕策略有更加深刻的認(rèn)識(shí),能夠根據(jù)不同的使用場(chǎng)景更加靈活的應(yīng)用。,更多關(guān)于ThreadPoolExecutor的八種拒絕策略的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 每日六道java新手入門(mén)面試題,通往自由的道路

    每日六道java新手入門(mén)面試題,通往自由的道路

    這篇文章主要為大家分享了最有價(jià)值的6道java面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,對(duì)hashCode方法的設(shè)計(jì)、垃圾收集的堆和代進(jìn)行剖析,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Spring中的HandlerMapping執(zhí)行流程詳解

    Spring中的HandlerMapping執(zhí)行流程詳解

    這篇文章主要介紹了Spring中的HandlerMapping執(zhí)行流程詳解,HandlerMapping在Spring MVC框架的jar包下面,他是處理映射器,為用戶(hù)發(fā)送的請(qǐng)求找到合適的Handler Adapter,它將會(huì)把請(qǐng)求映射為HandlerExecutionChain對(duì)象,需要的朋友可以參考下
    2023-08-08
  • Java Poi-tl根據(jù)模板導(dǎo)出Word文件

    Java Poi-tl根據(jù)模板導(dǎo)出Word文件

    這篇文章主要為大家詳細(xì)介紹了Java如何使用Poi-tl根據(jù)模板實(shí)現(xiàn)導(dǎo)出Word文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-03-03
  • Java設(shè)計(jì)模式中的建造者模式詳解

    Java設(shè)計(jì)模式中的建造者模式詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式中的建造者模式詳解,建造者模式使我們?nèi)粘9ぷ髦斜容^常見(jiàn)的一種設(shè)計(jì)模式,和工廠(chǎng)模式一樣屬于創(chuàng)建型設(shè)計(jì)模式,用于解耦對(duì)象創(chuàng)建和對(duì)象使用的邏輯,需要的朋友可以參考下
    2023-12-12
  • Spring AOP注解案例及基本原理詳解

    Spring AOP注解案例及基本原理詳解

    這篇文章主要介紹了Spring AOP注解案例及基本原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java與kotlin詳細(xì)對(duì)比

    Java與kotlin詳細(xì)對(duì)比

    這篇文章主要介紹了Java與kotlin詳細(xì)對(duì)比,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • 使用Spring Cache時(shí)設(shè)置緩存鍵的注意事項(xiàng)詳解

    使用Spring Cache時(shí)設(shè)置緩存鍵的注意事項(xiàng)詳解

    在現(xiàn)代的Web應(yīng)用中,緩存是提高系統(tǒng)性能和響應(yīng)速度的重要手段之一,Spring框架提供了強(qiáng)大的緩存支持,通過(guò)??@Cacheable??、??@CachePut??、??@CacheEvict??等注解可以方便地實(shí)現(xiàn)緩存功能,本文給大家介紹了使用Spring Cache時(shí)設(shè)置緩存鍵的注意事項(xiàng)
    2025-01-01
  • Java gbk轉(zhuǎn)utf-8

    Java gbk轉(zhuǎn)utf-8

    本文主要介紹了Java gbk轉(zhuǎn)utf-8的方法,具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • SpringBoot返回對(duì)象時(shí),如何將Long類(lèi)型轉(zhuǎn)換為String

    SpringBoot返回對(duì)象時(shí),如何將Long類(lèi)型轉(zhuǎn)換為String

    這篇文章主要介紹了SpringBoot返回對(duì)象時(shí),實(shí)現(xiàn)將Long類(lèi)型轉(zhuǎn)換為String,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • velocity顯示List與Map的方法詳細(xì)解析

    velocity顯示List與Map的方法詳細(xì)解析

    以下是對(duì)velocity顯示List與Map的方法進(jìn)行了詳細(xì)的介紹。需要的朋友可以過(guò)來(lái)參考下
    2013-08-08

最新評(píng)論

桐城市| 朝阳区| 鄂托克旗| 门头沟区| 屯门区| 合阳县| 沙洋县| 依兰县| 高清| 永兴县| 哈尔滨市| 安多县| 正定县| 宁化县| 裕民县| 石门县| 遵义市| 西安市| 专栏| 喀喇沁旗| 潢川县| 定结县| 黔江区| 安乡县| 平南县| 什邡市| 花垣县| 浦县| 年辖:市辖区| 南开区| 昂仁县| 渝中区| 建德市| 会理县| 胶州市| 拜泉县| 长寿区| 凤台县| 凤庆县| 诏安县| 威远县|