1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        線程池理念分析及其手寫

        共 1341字,需瀏覽 3分鐘

         ·

        2021-01-17 09:19

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

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

        ? 作者?|? 彼岸舞

        來源 |? urlify.cn/IjyQzq

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

        什么是線程池?

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

          為什么要使用線程池?

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

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

            3:提高線程的可管理性

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

            思想:

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

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

              3:外部傳入的任務(wù)數(shù)量大于線程的執(zhí)行個(gè)數(shù)是,多余的任務(wù)如何處理?emmm,用個(gè)容器存起來,用阻塞隊(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)線程的個(gè)數(shù)為5
        ????private?static?int?WORK_NUM?=?5;
        ????
        ????//?隊(duì)列默認(rèn)任務(wù)個(gè)數(shù)為100
        ????private?static?int?TASK_COUNT?=?100;

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

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

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

        ????//?創(chuàng)建線程池,worker_num為線程池中工作線程的個(gè)數(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ì)列,什么時(shí)候執(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方法,返回線程池信息:工作線程個(gè)數(shù)和已完成任務(wù)個(gè)數(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)的父類

              各個(gè)參數(shù)的意義

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

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

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

                TimeUnit unit:存活時(shí)間單位

                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ù)直接丟棄

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

                注意:剛初始化的線程池當(dāng)中是沒有線程的,只有當(dāng)往里面投遞任務(wù)才會(huì)創(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),還會(huì)嘗試停止正在運(yùn)行或者暫停任務(wù)的線程

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

          工作機(jī)制

            

        ?

        ?

            

            在加入任務(wù)的會(huì)后會(huì)先判斷一下當(dāng)前線程池中的核心線程數(shù)時(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í)型~計(jì)算密級(jí)型,拆分才有意義

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

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

            FixedThreadPool:

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

              

        ?

            SingleThreadExecutor

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

        ?

        ?      

        ?

        ?    CachedThreadPool

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

              

        ?

        ?    ScheduledThreadPool

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

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

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

              方法說明:

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

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

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

              兩者的區(qū)別:

                

                scheduleAtFixedRate任務(wù)超時(shí):

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

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

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

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

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

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

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

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

        ?  Executor框架圖

            

           Executor框架基本使用流程

             








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

        ??????

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


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

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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            中国一级黄色毛片 | 国产婬语对白在线视频露脸 | 国产在线第一页 | 五月天性爱视频 | 欧美黄色免费看 | 99精品网站 | 日逼网站免费观看 | 丁香婷婷激情综合五月天 | 靠逼免费视频 | 黄色片视频看看 |