<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>

          線程池理念分析及其手寫

          共 1341字,需瀏覽 3分鐘

           ·

          2021-01-17 09:19

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

          優(yōu)質(zhì)文章,第一時間送達(dá)

          ? 作者?|? 彼岸舞

          來源 |? urlify.cn/IjyQzq

          76套java從入門到精通實(shí)戰(zhàn)課程分享

          什么是線程池?

              線程池,thread pool,是一種線程使用模式

            為什么要使用線程池?

              1:降低資源的消耗,降低線程的創(chuàng)建和銷毀的資源消耗

              2:提高響應(yīng)速度,假設(shè)線程的創(chuàng)建時間為T1,執(zhí)行時間為T2,銷毀時間為T3,如果是自己創(chuàng)建線程必然會經(jīng)歷,這三個時間,那么如果創(chuàng)建+銷毀>執(zhí)行,就會有大量時間用在創(chuàng)建和銷毀上,而不是在執(zhí)行任務(wù)上,而線程池關(guān)注的就是調(diào)整T1和T3的時間,線程池可以免去T1和T3的時間

              3:提高線程的可管理性

            不如先來實(shí)現(xiàn)一個自己的線程池

              思想:

                1:為了優(yōu)化T1和T3的時間,在使用前,線程必須在池中已經(jīng)創(chuàng)建好了,并且可以保持住,既然要保存住,那么就需要一個容器

                2:里面的線程如果是只能跑已經(jīng)在內(nèi)部寫好的代碼,那么就沒有意義,所以它必須能接收外部的任務(wù),運(yùn)行這個任務(wù)

                3:外部傳入的任務(wù)數(shù)量大于線程的執(zhí)行個數(shù)是,多余的任務(wù)如何處理?emmm,用個容器存起來,用阻塞隊(duì)列吧,上一章剛寫了

              實(shí)現(xiàn)代碼: 

          package?com.xiangxue.ch6.mypool;

          import?java.util.LinkedList;
          import?java.util.List;
          import?java.util.concurrent.ArrayBlockingQueue;
          import?java.util.concurrent.BlockingQueue;

          /**
          ?*?類說明:自己線程池的實(shí)現(xiàn)
          ?*/
          public?class?MyThreadPool2?{
          ????//?線程池中默認(rèn)線程的個數(shù)為5
          ????private?static?int?WORK_NUM?=?5;
          ????
          ????//?隊(duì)列默認(rèn)任務(wù)個數(shù)為100
          ????private?static?int?TASK_COUNT?=?100;

          ????//?工作線程組
          ????private?WorkThread[]?workThreads;

          ????//?任務(wù)隊(duì)列,作為一個緩沖
          ????private?final?BlockingQueue?taskQueue;
          ????private?final?int?worker_num;//用戶在構(gòu)造這個池,希望的啟動的線程數(shù)

          ????//?創(chuàng)建具有默認(rèn)線程個數(shù)的線程池
          ????public?MyThreadPool2()?{
          ????????this(WORK_NUM,?TASK_COUNT);
          ????}

          ????//?創(chuàng)建線程池,worker_num為線程池中工作線程的個數(shù)
          ????public?MyThreadPool2(int?worker_num,?int?taskCount)?{
          ????????if?(worker_num?<=?0)?worker_num?=?WORK_NUM;
          ????????if?(taskCount?<=?0)?taskCount?=?TASK_COUNT;
          ????????this.worker_num?=?worker_num;
          ????????taskQueue?=?new?ArrayBlockingQueue<>(taskCount);
          ????????workThreads?=?new?WorkThread[worker_num];
          ????????for?(int?i?=?0;?i?????????????workThreads[i]?=?new?WorkThread();
          ????????????workThreads[i].start();
          ????????}
          ????????Runtime.getRuntime().availableProcessors();
          ????}


          ????//?執(zhí)行任務(wù),其實(shí)只是把任務(wù)加入任務(wù)隊(duì)列,什么時候執(zhí)行有線程池管理器決定
          ????public?void?execute(Runnable?task)?{
          ????????try?{
          ????????????taskQueue.put(task);
          ????????}?catch?(InterruptedException?e)?{
          ????????????e.printStackTrace();
          ????????}

          ????}


          ????//?銷毀線程池,該方法保證在所有任務(wù)都完成的情況下才銷毀所有線程,否則等待任務(wù)完成才銷毀
          ????public?void?destroy()?{
          ????????//?工作線程停止工作,且置為null
          ????????System.out.println("ready?close?pool.....");
          ????????for?(int?i?=?0;?i?????????????workThreads[i].stopWorker();
          ????????????workThreads[i]?=?null;//help?gc
          ????????}
          ????????taskQueue.clear();//?清空任務(wù)隊(duì)列
          ????}

          ????//?覆蓋toString方法,返回線程池信息:工作線程個數(shù)和已完成任務(wù)個數(shù)
          ????@Override
          ????public?String?toString()?{
          ????????return?"WorkThread?number:"?+?worker_num
          ????????????????+?"??wait?task?number:"?+?taskQueue.size();
          ????}

          ????/**
          ?????*?內(nèi)部類,工作線程
          ?????*/
          ????private?class?WorkThread?extends?Thread?{

          ????????@Override
          ????????public?void?run()?{
          ????????????Runnable?r?=?null;
          ????????????try?{
          ????????????????while?(!isInterrupted())?{
          ????????????????????r?=?taskQueue.take();
          ????????????????????if?(r?!=?null)?{
          ????????????????????????System.out.println(getId()?+?"?ready?exec?:"?+?r);
          ????????????????????????r.run();
          ????????????????????}
          ????????????????????r?=?null;//help?gc;
          ????????????????}
          ????????????}?catch?(Exception?e)?{
          ????????????????//?TODO:?handle?exception
          ????????????}
          ????????}

          ????????public?void?stopWorker()?{
          ????????????interrupt();
          ????????}

          ????}
          }

            JDK中的線程池和工作機(jī)制

              線程池的創(chuàng)建

                ThreadPoolExecutor,jdk所有線程池實(shí)現(xiàn)的父類

                各個參數(shù)的意義

                  int corePoolSize:線程池核心線程數(shù),池內(nèi)線程數(shù)

                  int maximumPoolSize:線程池允許的最大線程數(shù),如果阻塞隊(duì)列也滿了, ?maximumPoolSize?

                  long keepAliveTime:線程空閑下來的存活時間,這個數(shù)值,只有在線程池內(nèi)的線程數(shù)量 > corePoolSize的時候才會有作用,它決定著 >?corePoolSize數(shù)量的線程的空閑下來的存活時間

                  TimeUnit unit:存活時間單位

                  BlockingQueue?workQueue:保存任務(wù)的阻塞隊(duì)列

                  ThreadFactory threadFactory:創(chuàng)建線程的工廠,給新創(chuàng)建的線程賦予名字

                  RejectedExecutionHandler handler:?線程池的飽和策略,當(dāng)線程池的最大允許數(shù)被沾滿了,阻塞隊(duì)列也沾滿了,那么再放入任務(wù)如何處理

                    飽和策略:

                    AbortPolicy:直接拋出異常

                    CallerRunsPolicy:用調(diào)用者所在的線程執(zhí)行任務(wù)

                    DiscardOldestPolicy:丟棄阻塞隊(duì)列中最老的任務(wù),也就是最靠前的任務(wù)

                    DiscardPolicy:當(dāng)前任務(wù)直接丟棄

                    如果這個策略都不是你想要的,可以自己實(shí)現(xiàn) RejectedExecutionHandler?接口,來完成自己的策略,比如寫數(shù)據(jù)庫,寫日志,或者緩存到其他的里面,等以后再撿回來

                  注意:剛初始化的線程池當(dāng)中是沒有線程的,只有當(dāng)往里面投遞任務(wù)才會創(chuàng)建,如果想一行來就讓里面的線程數(shù)等于corePoolSize可以調(diào)用prestartAllCoreThreads方法

              提交任務(wù)

                void execute(Runnable command):用于提交無返回的任務(wù)

                Future submit(Callable task):用于提交帶返回值的任務(wù)

              關(guān)閉線程池

                shutdown(),shutdownNow()

                shutdownNow(),設(shè)置線程池的狀態(tài),還會嘗試停止正在運(yùn)行或者暫停任務(wù)的線程

                shutdown()設(shè)置線程池狀態(tài),只會中斷所有沒有執(zhí)行任務(wù)的線程

            工作機(jī)制

              

          ?

          ?

              

              在加入任務(wù)的會后會先判斷一下當(dāng)前線程池中的核心線程數(shù)時候小于corePoolSize,如果小于,創(chuàng)建新的線程如果大于嘗試放入阻塞隊(duì)列中,如果場入失敗,那么將嘗試創(chuàng)建新的線程用于運(yùn)行任務(wù),如果創(chuàng)建新的線程也失敗的話,那么將執(zhí)行飽和策略

            合理配置線程池

               根據(jù)任務(wù)的性質(zhì)來:計(jì)算密集型(CPU),IO密集型,混合型

              計(jì)算密集型:

                加密,大數(shù)分解,正則.....,線程數(shù)適當(dāng)小一些,

                最大推薦:機(jī)器的Cpu核心數(shù)+1,為什么要+1,防止頁缺失

                 JAVA獲取CPU核心數(shù): 

          Runtime.getRuntime().availableProcessors();

              IO密集型:

                讀取文件,數(shù)據(jù)庫連接,網(wǎng)絡(luò)通訊,線程數(shù)適當(dāng)大一些

                最大推薦:機(jī)器的CPU核心數(shù)*2

              混合型:

                盡量拆分,IO密集型遠(yuǎn)遠(yuǎn)大于計(jì)算密集型,拆分意義不大,IO密級型~計(jì)算密級型,拆分才有意義

              注意:隊(duì)列的選擇上應(yīng)該使用有界隊(duì)列,無界隊(duì)列可能會導(dǎo)致內(nèi)存溢出,OOM

            預(yù)定義的線程池:

              FixedThreadPool:

                創(chuàng)建固定線程數(shù)量的,適用于負(fù)載較重的服務(wù)器,使用了LinkedBlockingQueue作為阻塞隊(duì)列

                

          ?

              SingleThreadExecutor

                創(chuàng)建單個線程,需要保證順序執(zhí)行任務(wù),不會有多個線程活動,使用了LinkedBlockingQueue作為阻塞隊(duì)列

          ?

          ?      

          ?

          ?    CachedThreadPool

                會根據(jù)需要來創(chuàng)建新的線程,適用于執(zhí)行很多很短期異步任務(wù)的程序,使用了SynchronousQueue作為阻塞隊(duì)列

                

          ?

          ?    ScheduledThreadPool

                需要定期執(zhí)行周期任務(wù),Timer不建議使用了。

                newSingleThreadScheduledExecutor:只包含一個線程,只需要單個線程執(zhí)行周期任務(wù),保證順序的執(zhí)行各個任務(wù)

                newScheduledThreadPool 可以包含多個線程的,線程執(zhí)行周期任務(wù),適度控制后臺線程數(shù)量的時候

                方法說明:

                  schedule:只執(zhí)行一次,任務(wù)還可以延時執(zhí)行

                  scheduleAtFixedRate:提交固定時間間隔的任務(wù)

                  scheduleWithFixedDelay:提交固定延時間隔執(zhí)行的任務(wù)

                兩者的區(qū)別:

                  

                  scheduleAtFixedRate任務(wù)超時:

                  規(guī)定60s執(zhí)行一次,有任務(wù)執(zhí)行了80S,下個任務(wù)馬上開始執(zhí)行

                  第一個任務(wù) 時長 80s,第二個任務(wù)20s,第三個任務(wù) 50s

                  第一個任務(wù)第0秒開始,第80S結(jié)束;

                  第二個任務(wù)第80s開始,在第100秒結(jié)束;

                  第三個任務(wù)第120s秒開始,170秒結(jié)束

                  第四個任務(wù)從180s開始

                  參加代碼:ScheduleWorkerTime類,執(zhí)行效果如圖:

                  建議在提交給ScheduledThreadPoolExecutor的任務(wù)要住catch異常。

          ?  Executor框架圖

              

             Executor框架基本使用流程

               








          粉絲福利:Java從入門到入土學(xué)習(xí)路線圖

          ??????

          ??長按上方微信二維碼?2 秒


          感謝點(diǎn)贊支持下哈?

          瀏覽 37
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  无码人妻精品一区二区蜜桃91 | 美女被肏视频网站 | 成人无码 在线观看免费视频 | 久久久久国产视频 | 国产偷窥盗摄精品 |