<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          多線程之線程池 · 下

          共 5707字,需瀏覽 12分鐘

           ·

          2021-07-17 17:53


          前言

          線程池中這塊的內(nèi)容確實要比我預(yù)期的多,當(dāng)然也可能是我講的太細(xì)了,所以比較費字,但是這樣也好,不僅讓各位小伙伴能更清楚相關(guān)邏輯和原理,而且對我而言,讓我可以做到知其然知其所以然,從這個層面上來講,我覺得一切都值得,甚至還有點意外的收獲。

          今天是線程池相關(guān)知識點收官之作,今天的內(nèi)容完結(jié)后,基本上線程池這塊的內(nèi)容就可以告一段落了,今天主要從以下幾方面開展:

          • 線程池的其他參數(shù)
            • 線程工廠
            • 拒絕策略處理器

          好了,話不多說,讓我們直接開始吧。

          線程池

          線程工廠

          先看第一個參數(shù)——線程工廠,這個參數(shù)的作用是創(chuàng)建線程。在最開始的時候,我們創(chuàng)建線程池的時候并沒有指定這個參數(shù),但是構(gòu)造器內(nèi)部會自動為我們引入默認(rèn)的線程工廠:

          下面我們就來看下默認(rèn)的線程工廠是如何實現(xiàn)的:

          在線程工廠中,主要有兩部分的操作,第一部分就是設(shè)定創(chuàng)建線程時的信息,包括線程組、線程名稱、堆棧大??;第二部分主要是設(shè)置線程的優(yōu)先級,如果線程是守護(hù)線程的話,會把它修改為非守護(hù)線程(看到這里,我發(fā)現(xiàn)關(guān)于線程組、線程得好好補(bǔ)補(bǔ)課了,后面要跟進(jìn)下)。

          我們一般自定義線程工廠主要是為了修改線程名稱,這樣方便我們在排查問題的時候找到我們自己定義的線程池,我們要自頂一下線程工廠只需要沖洗ThreadFactorynewThread方法即可:

          static class MyThreadFactory implements ThreadFactory {
                  private static final AtomicInteger poolNumber = new AtomicInteger(1);
                  private final ThreadGroup group;
                  private final AtomicInteger threadNumber = new AtomicInteger(1);
                  private final String namePrefix;

                  MyThreadFactory() {
                      SecurityManager s = System.getSecurityManager();
                      group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
                      namePrefix = "syske-" +
                              poolNumber.getAndIncrement() +
                              "-thread-";
                  }

                  @Override
                  public Thread newThread(Runnable r) {
                      Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
                      if (t.isDaemon())
                          t.setDaemon(false);
                      if (t.getPriority() != Thread.NORM_PRIORITY)
                          t.setPriority(Thread.NORM_PRIORITY);
                      return t;
                  }
              }

          這里我就直接把默認(rèn)線程工廠的實現(xiàn)copy過來,然后只改了名字,然后在構(gòu)造線程池的時候傳入即可:

                  ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new MyThreadFactory());

          然后運行下,我們就會發(fā)現(xiàn)線程名稱已經(jīng)變成我們修改之后的了:

          當(dāng)然如果只是單純想修改線程池中線程名稱,這樣就太奢侈了,我們可以通過guava提供的ThreadFactoryBuilder直接修改(就是我們之前分享的guava):

          ThreadFactory build = new ThreadFactoryBuilder().setNameFormat("syske-task-%d").build();

          當(dāng)然,guava還可以設(shè)定其他屬性,甚至可以指定線程工廠,UncaughtExceptionHandler表示未捕獲到的異常處理器:

          拒絕策略(飽和策略)

          我們在之前的內(nèi)容中說過,如果任務(wù)數(shù)超過corePoolSize + maximumPoolSize + workQueue.size(),線程池就會報拒絕連接的錯誤,這個錯誤就是這里拋出了的,所以接下來我們要分享的就是線程池的最后一個參數(shù)——RejectedExecutionHandler。

          和線程工廠一樣,在我們不傳拒絕策略處理器的時候,其實構(gòu)造方法內(nèi)部為我們指定了默認(rèn)的處理器:

          默認(rèn)拒絕策略處理器的實現(xiàn)也很簡單:

          也可以說是簡單粗暴,直接就拋出了RejectedExecutionException異常。

          當(dāng)然我們也可以定義自己的拒絕策略處理器:

           static class MyRejectedExecutionHandler implements RejectedExecutionHandler {
                  @Override
                  public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                      System.out.println("線程池拒絕連接,資源已耗盡:r = " + r + ", executor = " + executor);
                      throw new RejectedExecutionException();
                  }
              }

          然后也是在構(gòu)造線程池的時候傳入:

          ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new MyThreadFactory(), new MyRejectedExecutionHandler());

          我們把工作對了調(diào)小,把循環(huán)次數(shù)調(diào)大,把休眠時間調(diào)長,然后運行就會觸發(fā)飽和策略,進(jìn)入我們的的rejectedExecution方法:

          根據(jù)我的測試,我發(fā)現(xiàn)如果在rejectedExecution方法中直接拋出RejectedExecutionException,會導(dǎo)致主線程進(jìn)入阻塞狀態(tài),這樣整個系統(tǒng)就卡死了

          但如果不拋出RejectedExecutionException異常的話,則不會導(dǎo)致阻塞:

          所以考慮到實際應(yīng)用情況,我覺得我們還是有必要重寫rejectedExecution方法的,而且我們在方法內(nèi)部還可以做一些業(yè)務(wù)操作,比如線程池擴(kuò)容,或者睡眠等待:

          或者可以做一些業(yè)務(wù)告警等操作。

          總結(jié)

          關(guān)于線程池的創(chuàng)建、參數(shù)以及參數(shù)的作用,經(jīng)過我們這兩天的詳細(xì)分析和演示,我想大家一定也對線程池有了新的認(rèn)知,應(yīng)該說在以后的工作和學(xué)習(xí)中,不論是線程池的使用還是解決線程池相關(guān)的問題,都可以站得更高,看的更遠(yuǎn)。

          當(dāng)然,最重要的是,這幾天分享的內(nèi)容都比較實用。明天我們會對線程池這塊做一個小結(jié),然后小結(jié)之外我們會有一些遺漏知識點的補(bǔ)充。好了,今天就先到這里吧!

          - END -


          瀏覽 42
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  a v 视频在线观看 | 美女操逼视频。 | 五月婷婷激情在线 | 国产精品一区二区人成电影网 | 在线视频你懂得 |