欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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)建,管理和回收呢?線程池可以實現(xiàn)該能力。

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

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

線程池的封裝實現(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的實現(xiàn)接口,提供延時,周期性執(zhí)行Future的能力,同時具備ExecutorService的基礎(chǔ)能力,通常不直接使用該類/
AbstractExecutorServiceAbstractExecutorService是個虛類,對ExecutorService中方法進(jìn)行了默認(rèn)實現(xiàn),其提供了newTaskFor函數(shù),用于獲取RunnableFuture對象,該對象實現(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é)點運(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ù)隊列,當(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ù)且等待隊列已滿時,就會采用拒絕處理策略處理新提交的任務(wù),不指定時,默認(rèn)的處理策略是AbortPolicy,即拋棄該任務(wù)

綜上,我們可以看出創(chuàng)建一個線程池最少需要明確核心線程數(shù),最大線程數(shù),超時時間及單位,等待隊列這五個參數(shù),下面我們創(chuàng)建一個核心線程數(shù)為1,最大線程數(shù)為3,5s超時回收,等待隊列最多能存放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:丟棄隊列頭部的舊任務(wù),然后嘗試重新執(zhí)行,如果再次失敗,重復(fù)該過程
  • CallerRunsPolicy:由調(diào)用線程處理該任務(wù)

當(dāng)然,如果上述拒絕策略不能滿足需求,我們也可以自定義異常,實現(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ù)隊列

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

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

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

非公平鎖與公平鎖

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

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

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

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

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

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

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

隊列名稱底層數(shù)據(jù)結(jié)構(gòu)默認(rèn)長度最大長度是否讀寫分離適用場景
ArrayBlockingQueue數(shù)組0開發(fā)者指定大小任務(wù)數(shù)量較少時使用
LinkedBlockingQueue鏈表Integer.MAX_VALUEInteger.MAX_VALUE大量任務(wù)時使用
SynchronousQueue公平鎖-隊列/非公平鎖-棧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的大數(shù)類(BigDecimal)和八種舍入模式

    介紹Java的大數(shù)類(BigDecimal)和八種舍入模式

    在實際應(yīng)用中,需要對更大或者更小的數(shù)進(jìn)行運(yùn)算和處理。Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數(shù)進(jìn)行精確的運(yùn)算。本文將介紹Java中的大數(shù)類BigDecimal及其八種舍入模式,有需要的可以參考借鑒。
    2016-08-08
  • java JOptionPane類的介紹

    java JOptionPane類的介紹

    java JOptionPane類的介紹,需要的朋友可以參考一下
    2013-04-04
  • springcloud feign調(diào)其他微服務(wù)時參數(shù)是對象的問題

    springcloud feign調(diào)其他微服務(wù)時參數(shù)是對象的問題

    這篇文章主要介紹了springcloud feign調(diào)其他微服務(wù)時參數(shù)是對象的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java System類兩個常用方法代碼實例

    Java System類兩個常用方法代碼實例

    這篇文章主要介紹了Java System類兩個常用方法代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • 使用SpringBoot 工廠模式自動注入到Map

    使用SpringBoot 工廠模式自動注入到Map

    這篇文章主要介紹了使用SpringBoot 工廠模式自動注入到Map,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 詳解如何使用SpringBoot的緩存@Cacheable

    詳解如何使用SpringBoot的緩存@Cacheable

    這篇文章主要為大家介紹了如何使用SpringBoot的緩存@Cacheable詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Spring Boot配置特定屬性spring.profiles的方法

    Spring Boot配置特定屬性spring.profiles的方法

    這篇文章主要介紹了Spring Boot配置特定屬性spring.profiles的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-11-11
  • SpringBoot使用mybatis-plus分頁查詢無效的問題解決

    SpringBoot使用mybatis-plus分頁查詢無效的問題解決

    MyBatis-Plus提供了很多便捷的功能,包括分頁查詢,本文主要介紹了SpringBoot使用mybatis-plus分頁查詢無效的問題解決,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • Spring中@Controller和@RestController的區(qū)別詳解

    Spring中@Controller和@RestController的區(qū)別詳解

    這篇文章主要介紹了Spring中@Controller和@RestController的區(qū)別詳解,@RestController?是?@Controller?和?@ResponseBody?的結(jié)合體,單獨使用?@RestController?的效果與?@Controller?和?@ResponseBody?二者同時使用的效果相同,需要的朋友可以參考下
    2023-10-10
  • java多線程模擬交通燈管理系統(tǒng)

    java多線程模擬交通燈管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java多線程模擬交通燈管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論