<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      詳細(xì)剖析Java動(dòng)態(tài)線程池的擴(kuò)容以及縮容操作

      前言

      在項(xiàng)目中,我們經(jīng)常會(huì)使用到線程來(lái)處理加快我們的任務(wù)。但為了節(jié)約資源,大多數(shù)程序員都會(huì)把線程進(jìn)行池化,使用線程池來(lái)更好的支持我們的業(yè)務(wù)。

      Java線程池ThreadPoolExecutor有幾個(gè)比較核心的參數(shù),如corePoolSize、maximumPoolSize等等。無(wú)論是在工作中還是在面試中,都會(huì)被問(wèn)到,如何正確的設(shè)置這幾個(gè)參數(shù)。

      線程池的參數(shù)并不好配置。一方面線程池的運(yùn)行機(jī)制不是很好理解,配置合理需要強(qiáng)依賴開(kāi)發(fā)人員的個(gè)人經(jīng)驗(yàn)和知識(shí)。項(xiàng)目IO密集型還是CPU密集型等等,總歸很難確定一個(gè)完美的參數(shù),此時(shí)就有了動(dòng)態(tài)線程池的誕生。

      動(dòng)態(tài)線程池(DTP)原理

      其實(shí)動(dòng)態(tài)線程池并不是很高大上的技術(shù),它底層依舊是依賴了ThreadPoolExecutor的一些核心接口方法。我們通過(guò)下面圖片可以很清楚的看到,ThreadPoolExecutor本身就給我們提供了很多鉤子方法,讓我們?nèi)ザㄖ苹?/p>

      那么其原理也非常簡(jiǎn)單了,我們?cè)谶\(yùn)行中假設(shè)有一個(gè)線程池叫做TaskExecutor

      1. 他的核心線程池默認(rèn)假設(shè)是10,現(xiàn)在我發(fā)覺(jué)不夠用了,此時(shí)我想把他的核心線程池調(diào)整為20
      2. 我可以寫一個(gè)遠(yuǎn)程配置(可以阿波羅,zk,redis什么都可以)。然后監(jiān)聽(tīng)到了這個(gè)配置變?yōu)榱薱ore.pool.size=20
      3. 然后我獲取到了這個(gè)線程池TaskExecutor,并且調(diào)用setCorePoolSize(20),那么這個(gè)TaskExecutor核心線程數(shù)就變?yōu)榱?0

      就是這么簡(jiǎn)單,撥開(kāi)表面,探究原理,內(nèi)部其實(shí)非常的簡(jiǎn)單。當(dāng)時(shí)公司里面的線程池還有加一些友好的界面、監(jiān)控告警、操作日志、權(quán)限校驗(yàn)、審核等等,但本質(zhì)就是監(jiān)聽(tīng)配置,然后調(diào)用setCorePoolSize方法去實(shí)現(xiàn)的,最大線程數(shù)類似。

      public void setCorePoolSize(int corePoolSize) {
          if (corePoolSize < 0)
              throw new IllegalArgumentException();
          int delta = corePoolSize - this.corePoolSize;
          this.corePoolSize = corePoolSize;
          if (workerCountOf(ctl.get()) > corePoolSize)
              interruptIdleWorkers();
          else if (delta > 0) {
              int k = Math.min(delta, workQueue.size());
              while (k-- > 0 && addWorker(null, true)) {
                  if (workQueue.isEmpty())
                      break;
              }
          }
      }
      

      動(dòng)態(tài)線程池縮容

      首先提出幾個(gè)問(wèn)題

      1. 核心線程數(shù)為5,現(xiàn)在有3個(gè)線程在執(zhí)行,并且沒(méi)有執(zhí)行完畢,我修改核心線程數(shù)為4,是否修改成功
      2. 核心線程數(shù)為5,現(xiàn)在有3個(gè)線程在執(zhí)行,并且沒(méi)有執(zhí)行完畢,我修改核心線程數(shù)為1,是否修改成功

      讓我們帶著疑問(wèn)去思考問(wèn)題。

      1. 首先第一個(gè)問(wèn)題,因?yàn)楹诵木€程池?cái)?shù)為5,僅有3個(gè)在執(zhí)行,我修改為4,那么因?yàn)橛?個(gè)空閑的線程,它只需要銷毀1個(gè)空閑線程即可,因此是成功的
      2. 第二個(gè)問(wèn)題,核心線程池?cái)?shù)為5,僅有3個(gè)在執(zhí)行,我修改為1。雖然有2個(gè)空閑線程,但是我需要銷毀4個(gè)線程。因?yàn)橛?個(gè)空閑線程,2個(gè)非空閑線程。我只能銷毀2個(gè)空閑線程,另外2個(gè)執(zhí)行的任務(wù)不能被打斷,也就是執(zhí)行后仍然為3個(gè)核心線程數(shù)。
      3. 那什么時(shí)候銷毀剩下2個(gè)執(zhí)行的線程呢,等到2個(gè)執(zhí)行的任務(wù)完畢之后,就會(huì)銷毀它了。假設(shè)這個(gè)任務(wù)是一個(gè)死循環(huán),永遠(yuǎn)不會(huì)結(jié)束,那么核心線程數(shù)永遠(yuǎn)是3,永遠(yuǎn)不能設(shè)置為1

      我們舉一個(gè)代碼的例子如下

      ThreadPoolExecutor es = new ThreadPoolExecutor(5, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
      es.prestartAllCoreThreads();  // 預(yù)啟動(dòng)所有核心線程
      
      // 啟動(dòng)三個(gè)任務(wù),執(zhí)行次數(shù)不一樣
      for (int i = 0; i < 3; i++) {
          int finalI = i;
          es.execute(() -> {
              int cnt = 0;
              while (true) {
                  try {
                      cnt++;
                      TimeUnit.SECONDS.sleep(2);
      
                      if (cnt > finalI + 1) {
                          log.info(Thread.currentThread().getName() + " 執(zhí)行完畢");
                          break;
                      }
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          });
      }
      TimeUnit.SECONDS.sleep(1);  // 等待線程池中的線程執(zhí)行
      log.info("修改前 es = {}", es);  // 這里核心線程數(shù)必定是5
      
      es.setCorePoolSize(1);  // 修改核心線程數(shù)為1,但是核心線程數(shù)為5,并且有3個(gè)線程在執(zhí)行任務(wù),
      
      while (true) {
          TimeUnit.SECONDS.sleep(1); // 等待
          log.info("修改后 es = {}", es);
      }
      

      輸出結(jié)果為如下

      // 修改前核心線程數(shù)為5,運(yùn)行線程數(shù)為3
      [修改前 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 5, active threads = 3, queued tasks = 0, completed tasks = 0]]
      
      // 因?yàn)橛?個(gè)空閑線程,先把2個(gè)空閑線程給銷毀了,剩下3個(gè)線程
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]]
      
      // 等第1個(gè)任務(wù)執(zhí)行完畢,剩下2個(gè)線程
      [Main.lambda$d$0:38] [pool-2-thread-1 執(zhí)行完畢]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 1]]
      
      // 等第2個(gè)任務(wù)執(zhí)行完畢,剩下1個(gè)線程
      [Main.lambda$d$0:38] [pool-2-thread-2 執(zhí)行完畢]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 2]]
      
      // 等第3個(gè)任務(wù)執(zhí)行完畢,剩下1個(gè)線程。因?yàn)槲倚薷牡木褪?個(gè)核心線程
      [Main.lambda$d$0:38] [pool-2-thread-3 執(zhí)行完畢]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 1, active threads = 0, queued tasks = 0, completed tasks = 3]]
      
      

      有興趣的讀者可以拿這塊帶去自己去試試,輸出結(jié)果里面的注釋 我寫的非常詳細(xì),大家可以詳細(xì)品品這塊輸出結(jié)果。

      動(dòng)態(tài)線程池?cái)U(kuò)容

      擴(kuò)容我就不提問(wèn)問(wèn)題了,和縮容異曲同工,但我希望讀者可以先看下以下代碼,不要看答案,認(rèn)為會(huì)輸出什么結(jié)果,看下是否和自己想的是否一樣,如果一樣,那說(shuō)明你已經(jīng)完全懂了,如果不一樣,是什么原因。

      // 核心線程數(shù)1,最大線程數(shù)10
      ThreadPoolExecutor es = new ThreadPoolExecutor(1, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
      es.prestartAllCoreThreads();  // 預(yù)啟動(dòng)所有核心線程
      
      for (int i = 0; i < 5; i++) {
          int finalI = i;
          es.execute(() -> {
              int cnt = 0;
              while (true) {
                  try {
                      cnt++;
                      TimeUnit.SECONDS.sleep(2);
      
                      if (cnt > finalI + 1) {
                          log.info(Thread.currentThread().getName() + " 執(zhí)行完畢");
                          break;
                      }
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          });
      }
      
      TimeUnit.SECONDS.sleep(1);  // 等待線程池中的線程執(zhí)行
      log.info("修改前 es = {}", es);  // 這里核心線程數(shù)必定是1, 隊(duì)列里面有4個(gè)任務(wù)
      
      es.setCorePoolSize(3);  // 修改核心線程數(shù)為3
      
      while (true) {
          TimeUnit.SECONDS.sleep(1); // 等待
          log.info("修改后 es = {}", es);
      }   
      

      輸出結(jié)果為如下 (注意觀察輸出queued tasks的變化?。?!

      [修改前 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 1, active threads = 1, queued tasks = 4, completed tasks = 0]]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 3, queued tasks = 2, completed tasks = 0]]
      
      [Main.lambda$a$1:73] [pool-2-thread-1 執(zhí)行完畢]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 3, queued tasks = 1, completed tasks = 1]]
      
      [Main.lambda$a$1:73] [pool-2-thread-2 執(zhí)行完畢]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 2]]
      
      [Main.lambda$a$1:73] [pool-2-thread-3 執(zhí)行完畢]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 2, queued tasks = 0, completed tasks = 3]]
      
      [Main.lambda$a$1:73] [pool-2-thread-1 執(zhí)行完畢]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 1, queued tasks = 0, completed tasks = 4]]
      
      [Main.lambda$a$1:73] [pool-2-thread-2 執(zhí)行完畢]
      [修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 0, queued tasks = 0, completed tasks = 5]]
      

      最后

      在業(yè)務(wù)中,我們?yōu)榱颂岣咝适褂昧司€程,為了加快線程我們使用了線程池,而又為了更好的利用線程池的資源,我們又實(shí)現(xiàn)了動(dòng)態(tài)化線程池。這也就是遇到問(wèn)題、探索問(wèn)題、解決問(wèn)題的一套思路吧。

      我們從底層原理分析,發(fā)現(xiàn)動(dòng)態(tài)線程池的底層原理非常簡(jiǎn)單,希望大家不要恐懼,往往撥開(kāi)外衣,發(fā)現(xiàn)里面最根本的原理,才能是我們更好的捋清楚其中的邏輯。希望本文提供的動(dòng)態(tài)化線程池思路能對(duì)大家有幫助。

      最終也極力希望讀者朋友們,可以將上述兩個(gè)例子詳細(xì)分析一下原因,相信會(huì)有不小的進(jìn)步,謝謝大家。

      posted @ 2025-01-23 16:31  程序員博博  閱讀(468)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 午夜福利国产区在线观看| 国产精品视频一区不卡| 国产亚洲精品第一综合另类无码无遮挡又大又爽又黄的视频 | 日本欧美一区二区三区在线播放| 武装少女在线观看高清完整版免费| 巨熟乳波霸若妻在线播放| 国产精品自在线拍国产手机版| 久久99精品久久久大学生| 亚洲成在人线在线播放无码| 特级毛片a片久久久久久| 久久精产国品一二三产品| 亚洲伊人久久综合影院| 久久国产乱子伦免费精品| 国产精品免费中文字幕| 人妻av中文字幕无码专区| 久久96热在精品国产高清| 推油少妇久久99久久99久久| 人妻va精品va欧美va| 国内熟女中文字幕第一页| 日韩女同在线二区三区| 国产呻吟久久久久久久92| 国产伦精品一区二区亚洲| 国产成人精品久久一区二| 人妻系列无码专区69影院| 伊人久久精品久久亚洲一区| 亚洲国产精品久久久久婷婷图片| 精品国产一区二区三区久| 国产区精品福利在线观看精品| 国内精品伊人久久久久777 | 成人片黄网站a毛片免费| 亚洲深深色噜噜狠狠网站| 四虎精品国产精品亚洲精| 国产精品久久久久影院亚瑟| 国产网红女主播精品视频| 精品一区二区三区四区色| 亚洲一区二区三成人精品| 中文字幕日韩精品人妻| 久爱www人成免费网站| 91精品国产老熟女在线| 久久精品国产99国产精品澳门| 老熟妇性老熟妇性色|