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

java 線程池封裝及拒絕策略示例詳解

 更新時間:2022年12月14日 11:01:06   作者:小海編碼日記  
這篇文章主要為大家介紹了java 線程池封裝及拒絕策略示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前文

提到線程的使用以及線程間通信方式,通常情況下我們通過new Thread或者new Runnable創(chuàng)建線程,這種情況下,需要開發(fā)者手動管理線程的創(chuàng)建和回收,線程對象沒有復(fù)用,大量的線程對象創(chuàng)建與銷毀會引起頻繁GC,那么事否有機(jī)制自動進(jìn)行線程的創(chuàng)建,管理和回收呢?線程池可以實(shí)現(xiàn)該能力。

線程池的優(yōu)點(diǎn):

  • 線程池中線程重用,避免線程創(chuàng)建和銷毀帶來的性能開銷
  • 能有效控制線程數(shù)量,避免大量線程搶占資源造成阻塞
  • 對線程進(jìn)行簡單管理,提供定時執(zhí)行預(yù)計(jì)指定間隔執(zhí)行等策略

線程池的封裝實(shí)現(xiàn)

在java.util.concurrent包中提供了一系列的工具類以方便開發(fā)者創(chuàng)建和使用線程池,這些類的繼承關(guān)系及說明如下:

類名說明備注
ExecutorExecutor接口提供了一種任務(wù)提交后的執(zhí)行機(jī)制,包括線程的創(chuàng)建與運(yùn)行,線程調(diào)度等,通常不直接使用該類/
ExecutorServiceExecutorService接口,提供了創(chuàng)建,管理,終止Future執(zhí)行的方法,用于跟蹤一個或多個異步任務(wù)的進(jìn)度,通常不直接使用該類/
ScheduledExecutorServiceExecutorService的實(shí)現(xiàn)接口,提供延時,周期性執(zhí)行Future的能力,同時具備ExecutorService的基礎(chǔ)能力,通常不直接使用該類/
AbstractExecutorServiceAbstractExecutorService是個虛類,對ExecutorService中方法進(jìn)行了默認(rèn)實(shí)現(xiàn),其提供了newTaskFor函數(shù),用于獲取RunnableFuture對象,該對象實(shí)現(xiàn)了submit,invokeAny和invokeAll方法,通常不直接使用該類/
ThreadPoolExecutor通過創(chuàng)建該類對象就可以構(gòu)建一個線程池,通過調(diào)用execute方法可以向該線程池提交任務(wù)。通常情況下,開發(fā)者通過自定義參數(shù),構(gòu)造該類對象就來獲得一個符合業(yè)務(wù)需求的線程池/
ScheduledThreadPoolExecutor通過創(chuàng)建該類對象就可以構(gòu)建一個可以周期性執(zhí)行任務(wù)的線程池,通過調(diào)用schedule,scheduleWithFixedDelay等方法可以向該線程池提交任務(wù)并在指定時間節(jié)點(diǎn)運(yùn)行。通常情況下,開發(fā)者通過構(gòu)造該類對象就來獲得一個符合業(yè)務(wù)需求的可周期性執(zhí)行任務(wù)的線程池/

由上表可知,對于開發(fā)者而言,通常情況下我們可以通過構(gòu)造ThreadPoolExecutor對象來獲取一個線程池對象,通過其定義的execute方法來向該線程池提交任務(wù)并執(zhí)行,那么怎么創(chuàng)建線程池呢?讓我們一起看下

ThreadPoolExecutor

ThreadPoolExecutor完整參數(shù)的構(gòu)造函數(shù)如下所示:

     /**
      * Creates a new {@code ThreadPoolExecutor} with the given initial
      * parameters.
      *
      * @param corePoolSize the number of threads to keep in the pool, even
      *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
      * @param maximumPoolSize the maximum number of threads to allow in the
      *        pool
      * @param keepAliveTime when the number of threads is greater than
      *        the core, this is the maximum time that excess idle threads
      *        will wait for new tasks before terminating.
      * @param unit the time unit for the {@code keepAliveTime} argument
      * @param workQueue the queue to use for holding tasks before they are
      *        executed.  This queue will hold only the {@code Runnable}
      *        tasks submitted by the {@code execute} method.
      * @param threadFactory the factory to use when the executor
      *        creates a new thread
      * @param handler the handler to use when execution is blocked
      *        because the thread bounds and queue capacities are reached
      * @throws IllegalArgumentException if one of the following holds:<br>
      *         {@code corePoolSize < 0}<br>
      *         {@code keepAliveTime < 0}<br>
      *         {@code maximumPoolSize <= 0}<br>
      *         {@code maximumPoolSize < corePoolSize}
      * @throws NullPointerException if {@code workQueue}
      *         or {@code threadFactory} or {@code handler} is null
      */
     public ThreadPoolExecutor(int corePoolSize,
                               int maximumPoolSize,
                               long keepAliveTime,
                               TimeUnit unit,
                               BlockingQueue<Runnable> workQueue,
                               ThreadFactory threadFactory,
                               RejectedExecutionHandler handler) {
         if (corePoolSize < 0 ||
             maximumPoolSize <= 0 ||
             maximumPoolSize < corePoolSize ||
             keepAliveTime < 0)
             throw new IllegalArgumentException();
         if (workQueue == null || threadFactory == null || handler == null)
             throw new NullPointerException();
         this.acc = System.getSecurityManager() == null ?
                 null :
                 AccessController.getContext();
         this.corePoolSize = corePoolSize;
         this.maximumPoolSize = maximumPoolSize;
         this.workQueue = workQueue;
         this.keepAliveTime = unit.toNanos(keepAliveTime);
         this.threadFactory = threadFactory;
         this.handler = handler;
     }

從上述代碼可以看出,在構(gòu)建ThreadPoolExecutor時,主要涉及以下參數(shù):

  • corePoolSize:核心線程個數(shù),一般情況下可以使用 處理器個數(shù)/2 作為核心線程數(shù)的取值,可以通過Runtime.getRuntime().availableProcessors()來獲取處理器個數(shù)
  • maximumPoolSize:最大線程個數(shù),該線程池支持同時存在的最大線程數(shù)量
  • keepAliveTime:非核心線程閑置時的超時時長,超過這個時長,非核心線程就會被回收,我們也可以通過allowCoreThreadTimeOut(true)來設(shè)置核心線程閑置時,在超時時間到達(dá)后回收
  • unit:keepAliveTime的時間單位
  • workQueue:線程池中的任務(wù)隊(duì)列,當(dāng)核心線程數(shù)滿或最大線程數(shù)滿時,通過線程池的execute方法提交的Runnable對象存儲在這個參數(shù)中,遵循先進(jìn)先出原則
  • threadFactory:創(chuàng)建線程的工廠 ,用于批量創(chuàng)建線程,統(tǒng)一在創(chuàng)建線程時進(jìn)行一些初始化設(shè)置,如是否守護(hù)線程、線程的優(yōu)先級等。不指定時,默認(rèn)使用Executors.defaultThreadFactory() 來創(chuàng)建線程,線程具有相同的NORM_PRIORITY優(yōu)先級并且是非守護(hù)線程
  • handler:任務(wù)拒絕處理策略,當(dāng)線程數(shù)量等于最大線程數(shù)且等待隊(duì)列已滿時,就會采用拒絕處理策略處理新提交的任務(wù),不指定時,默認(rèn)的處理策略是AbortPolicy,即拋棄該任務(wù)

綜上,我們可以看出創(chuàng)建一個線程池最少需要明確核心線程數(shù),最大線程數(shù),超時時間及單位,等待隊(duì)列這五個參數(shù),下面我們創(chuàng)建一個核心線程數(shù)為1,最大線程數(shù)為3,5s超時回收,等待隊(duì)列最多能存放5個任務(wù)的線程池,代碼如下:

 ThreadPoolExecutor executor = new ThreadPoolExecutor(1,3,5,TimeUnit.SECONDS,new LinkedBlockingQueue<>(5));

隨后我們使用for循環(huán)向該executor中提交任務(wù),代碼如下:

 public static void main(String[] args) {
     // 創(chuàng)建線程池
     ThreadPoolExecutor executor = new ThreadPoolExecutor(1,3,5,TimeUnit.SECONDS,new LinkedBlockingQueue<>(5));
     for (int i=0;i<10;i++) {
         int finalI = i;
         System.out.println("put runnable "+ finalI +"to executor");
         // 向線程池提交任務(wù)
         executor.execute(new Runnable() {
             @Override
             public void run() {
                 System.out.println(Thread.currentThread().getName()+",runnable "+ finalI +"start");
                 try {
                     Thread.sleep(5000);
                 } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                 }
                 System.out.println(Thread.currentThread().getName()+",runnable "+ finalI +"executed");
             }
         });
     }
 }

輸出如下:

從輸出可以看到,當(dāng)提交一個任務(wù)到線程池時,其執(zhí)行流程如下:

線程池拒絕策略

線程池拒絕策略有四類,定義在ThreadPoolExecutor中,分別是:

  • AbortPolicy:默認(rèn)拒絕策略,丟棄提交的任務(wù)并拋出RejectedExecutionException,在該異常輸出信息中,可以看到當(dāng)前線程池狀態(tài)
  • DiscardPolicy:丟棄新來的任務(wù),但是不拋出異常
  • DiscardOldestPolicy:丟棄隊(duì)列頭部的舊任務(wù),然后嘗試重新執(zhí)行,如果再次失敗,重復(fù)該過程
  • CallerRunsPolicy:由調(diào)用線程處理該任務(wù)

當(dāng)然,如果上述拒絕策略不能滿足需求,我們也可以自定義異常,實(shí)現(xiàn)RejectedExecutionHandler接口,即可創(chuàng)建自己的線程池拒絕策略,下面是使用自定義拒絕策略的示例代碼:

 public static void main(String[] args) {
     RejectedExecutionHandler handler = new RejectedExecutionHandler() {
         @Override
         public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
             System.out.println("runnable " + r +" in executor "+executor+" is refused");
         }
     };
     ThreadPoolExecutor executor = new ThreadPoolExecutor(1,3,5,TimeUnit.SECONDS,new LinkedBlockingQueue<>(5),handler);
     for (int i=0;i<10;i++) {
         int finalI = i;
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
                 System.out.println(Thread.currentThread().getName()+",runnable "+ finalI +"start");
                 try {
                     Thread.sleep(5000);
                 } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                 }
                 System.out.println(Thread.currentThread().getName()+",runnable "+ finalI +"executed");
             }
         };
         System.out.println("put runnable "+ runnable+"  index:"+finalI +" to executor:"+executor);
         executor.execute(runnable);
     }
 }

輸出如下:

任務(wù)隊(duì)列

對于線程池而言,任務(wù)隊(duì)列需要是BlockingQueue的實(shí)現(xiàn)類,BlockingQueue接口的實(shí)現(xiàn)類類圖如下:

下面我們針對常用隊(duì)列做簡單了解:

ArrayBlockingQueue:ArrayBlockingQueue是基于數(shù)組的阻塞隊(duì)列,在其內(nèi)部維護(hù)一個定長數(shù)組,所以使用ArrayBlockingQueue時必須指定任務(wù)隊(duì)列長度,因?yàn)椴徽搶?shù)據(jù)的寫入或者讀取都使用的是同一個鎖對象,所以沒有實(shí)現(xiàn)讀寫分離,同時在創(chuàng)建時我們可以指定鎖內(nèi)部是否采用公平鎖,默認(rèn)實(shí)現(xiàn)是非公平鎖。

非公平鎖與公平鎖

公平鎖:多個任務(wù)阻塞在同一鎖時,等待時長長的優(yōu)先獲取鎖

非公平鎖:多個任務(wù)阻塞在同一鎖時,鎖可獲取時,一起搶鎖,誰先搶到誰先執(zhí)行

LinkedBlockingQueue:LinkedBlockingQueue是基于鏈表的阻塞隊(duì)列,在創(chuàng)建時可不指定任務(wù)隊(duì)列長度,默認(rèn)值是Integer.MAX_VALUE,在LinkedBlockingQueue中讀鎖和寫鎖實(shí)現(xiàn)了分支,相對ArrayBlockingQueue而言,效率提升明顯。

SynchronousQueue:SynchronousQueue是一個不存儲元素的阻塞隊(duì)列,也就是說當(dāng)需要插入元素時,必須等待上一個元素被移出,否則不能插入,其適用于任務(wù)多但是執(zhí)行比較快的場景。

PriorityBlockingQueue:PriorityBlockingQueue是一個支持指定優(yōu)先即的阻塞隊(duì)列,默認(rèn)初始化長度為11,最大長度為Integer.MAX_VALUE - 8,可以通過讓裝入隊(duì)列的對象實(shí)現(xiàn)Comparable接口,定義對象排序規(guī)則來指定隊(duì)列中元素優(yōu)先級,優(yōu)先級高的元素會被優(yōu)先取出。

DelayQueue:DelayQueue是一個帶有延遲時間的阻塞隊(duì)列,隊(duì)列中的元素,只有等待延時時間到了才可以被取出,由于其內(nèi)部用PriorityBlockingQueue維護(hù)數(shù)據(jù),故其長度與PriorityBlockingQueue一致。一般用于定時調(diào)度類任務(wù)。

下表從一些角度對上述隊(duì)列進(jìn)行了比較:

隊(duì)列名稱底層數(shù)據(jù)結(jié)構(gòu)默認(rèn)長度最大長度是否讀寫分離適用場景
ArrayBlockingQueue數(shù)組0開發(fā)者指定大小任務(wù)數(shù)量較少時使用
LinkedBlockingQueue鏈表Integer.MAX_VALUEInteger.MAX_VALUE大量任務(wù)時使用
SynchronousQueue公平鎖-隊(duì)列/非公平鎖-棧0/任務(wù)多但是執(zhí)行速度快的場景
PriorityBlockingQueue對象數(shù)組11Integer.MAX_VALUE-8有任務(wù)需要優(yōu)先處理的場景
DelayQueue對象數(shù)組11Integer.MAX_VALUE-8定時調(diào)度類場景

以上就是java 線程池封裝及拒絕策略示例詳解的詳細(xì)內(nèi)容,更多關(guān)于java 線程池封裝拒絕策略的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JAVA PDF操作之實(shí)現(xiàn)截取N頁和多個PDF合并

    JAVA PDF操作之實(shí)現(xiàn)截取N頁和多個PDF合并

    這篇文章主要為大家詳細(xì)介紹了java關(guān)于PDF的一些操作,例如截取N頁并生成新文件,轉(zhuǎn)圖片以及多個PDF合并,文中的示例代碼講解詳細(xì),感興趣的可以了解下
    2025-01-01
  • java簡單實(shí)現(xiàn)數(shù)組的增刪改查方法

    java簡單實(shí)現(xiàn)數(shù)組的增刪改查方法

    這篇文章主要介紹了Java數(shù)組的增刪改查的示例,幫助大家更好的利用Java處理數(shù)據(jù),感興趣的朋友可以了解下,希望能給你帶來幫助
    2021-07-07
  • Java ArrayList與LinkedList及HashMap容器的用法區(qū)別

    Java ArrayList與LinkedList及HashMap容器的用法區(qū)別

    這篇文章主要介紹了Java ArrayList與LinkedList及HashMap容器的用法區(qū)別,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-07-07
  • Spring框架JdbcTemplate數(shù)據(jù)庫事務(wù)管理完全注解方式

    Spring框架JdbcTemplate數(shù)據(jù)庫事務(wù)管理完全注解方式

    這篇文章主要介紹了Spring框架JdbcTemplate數(shù)據(jù)庫事務(wù)管理及完全注解方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • SpringMVC整合SpringSession 實(shí)現(xiàn)sessiong

    SpringMVC整合SpringSession 實(shí)現(xiàn)sessiong

    這篇文章主要介紹了SpringMVC整合SpringSession 實(shí)現(xiàn)session的實(shí)例代碼,本文通過實(shí)例相結(jié)合的形式給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2018-04-04
  • elasticsearch kibana簡單查詢講解

    elasticsearch kibana簡單查詢講解

    今天小編就為大家分享一篇關(guān)于elasticsearch kibana簡單查詢講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • mybatis的映射xml中動態(tài)設(shè)置orderby方式

    mybatis的映射xml中動態(tài)設(shè)置orderby方式

    這篇文章主要介紹了mybatis的映射xml中動態(tài)設(shè)置orderby方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • CGLIB代理的使用與原理解析

    CGLIB代理的使用與原理解析

    這篇文章主要介紹了CGLIB代理的使用與原理解析,靜態(tài)代理和JDK 代理模式都要求目標(biāo)對象是實(shí)現(xiàn)一個接口,但是有時候目標(biāo)對象只是一個單獨(dú)的對象,并沒有實(shí)現(xiàn)任何的接口,這個時候可使用目標(biāo)對象子類來實(shí)現(xiàn)代理,這就是Cglib代理,需要的朋友可以參考下
    2023-09-09
  • MyBatis里映射文件sql語句爆紅問題及解決方案

    MyBatis里映射文件sql語句爆紅問題及解決方案

    文章介紹了在MyBatis映射文件中SQL語句爆紅的問題及其解決方法,解決方法是在設(shè)置中將SQL的全局方言設(shè)為None,然后應(yīng)用并確認(rèn)設(shè)置即可
    2025-03-03
  • Java獲取時間差(天數(shù)差,小時差,分鐘差)代碼示例

    Java獲取時間差(天數(shù)差,小時差,分鐘差)代碼示例

    這篇文章主要介紹了Java獲取時間差(天數(shù)差,小時差,分鐘差)代碼示例,使用SimpleDateFormat來實(shí)現(xiàn)的相關(guān)代碼,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11

最新評論

枝江市| 岳阳市| 察雅县| 石林| 图们市| 万源市| 东乌| 怀来县| 巩义市| 内黄县| 汶上县| 三台县| 高要市| 永嘉县| 星座| 泾阳县| 宜州市| 南平市| 稻城县| 应城市| 大理市| 湘潭县| 淮安市| 定结县| 佛教| 湘阴县| 易门县| 大安市| 陕西省| 慈溪市| 巴楚县| 曲阜市| 卢氏县| 页游| 商水县| 吉木乃县| 芦山县| 瓮安县| 多伦县| 滨州市| 万盛区|