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>

        線程池調(diào)優(yōu)原來這么簡單!

        共 1151字,需瀏覽 3分鐘

         ·

        2021-11-12 06:22

        點擊上方“Java金融”,選擇“設為星標”

        后臺回復"888"獲取bat面試題集

        原文|https://t.hk.uy/awez

        背景:

        最近的一個項目需要用到招標,臨時加了給我們的系統(tǒng)增加了一個性能需求,多少呢?一秒鐘300次NTP(不知道ntp的同學可以百度一下),平均3ms一次啊,沒測試過,心里沒有底。(⊙o⊙)…

        情境介紹:

        系統(tǒng)是一個時間服務器系統(tǒng),客戶端就是window系統(tǒng),或者其他的一些服務器,來向時間服務器同步時間。

        在這里插入圖片描述

        默認的window會向這個time.winodows.com進行時間同步,當然你也可以換成其他時間同步服務器。

        劃重點了:服務端NTP接口采用的是netty框架寫的一個接口,netty想必大家都了解的吧,nio通信,性能超好的。

        測試代碼是使用Executors.newFixedThreadPool寫的客戶端,10個線程數(shù)發(fā)送ntp包

        第一次測試

        數(shù)據(jù)庫連連接池最大設置為40個,測試結(jié)果倆一秒鐘28次,是的你沒有看錯,連十分之一都沒有,怎么這么差勁啊達不到預期啊,不行啊,這不就達不到要求的了嗎,得改啊,哪里改啊,怎么改啊?回到代碼中去,順藤摸瓜找到具體業(yè)務類,就是繼承SimpleChannelInboundHandler的類,從頭到尾打量了一下業(yè)務代碼,發(fā)現(xiàn)業(yè)務主要是構(gòu)造返回消息,記錄日志。構(gòu)造返回就是Java里的構(gòu)造對象什么的,根本不耗時的。         那就想不是有記錄日志嗎,不往數(shù)據(jù)庫里面寫東西了,把它注釋掉,跑一遍試試看。

        第二遍測試

        哎呦媽呀,起飛了老鐵,直接飆到了每秒鐘2萬次。

        看到這個令人驚訝的數(shù)據(jù),這遠遠超過要求啊,哈哈哈,妥妥的。突然一想,不對啊,這好像和產(chǎn)品設計不符合啊,設計里是要求記錄日志的啊,這個是有點濫竽充數(shù)啊,不行不行,這個得改。仔細分析一下,日志得寫到數(shù)據(jù)庫,讀了《java高并發(fā)程序設計》,心想是不是可以用異步的方式記錄日志呢,弄一個線程池吧。阿里巴巴JAVA開發(fā)手冊里是不推薦使用Executors中的現(xiàn)成的線程池的(具體原因我就不說了,可以看一下),那就自己寫一個吧。

        第三次測試

        考慮到任務提交速度快的原因,第一次構(gòu)造線程池采用了直接提交的隊列,這樣任務處理的快一些

        private?static?ExecutorService?saveThreadPool?=?new?ThreadPoolExecutor(2,?100,?60L,?TimeUnit.SECONDS,
        new?SynchronousQueueExecutors.defaultThreadFactory(),
        new?ThreadPoolExecutor.DiscardPolicy());

        測試代碼再跑一遍,哎呦媽呀,又起飛了老鐵!

        心想我這么牛逼的嗎,這隨便寫個線程池就OK了。在服務器執(zhí)行了top一看,不得了:這個cpu直接占滿了,系統(tǒng)里還有其他服務的,不能把資源全都給它啊。這次留了個心眼看了下數(shù)據(jù)庫日志,不對啊,沒有全部記錄啊,尼瑪發(fā)了一百多萬結(jié)果只記錄了幾萬條,這個差太多了啊。為什么漏掉了呢,回過頭來繼續(xù)看線程池的構(gòu)造。終于發(fā)現(xiàn)了紕漏,拒絕策略是用了new ThreadPoolExecutor.DiscardPolicy(),這個可出事了啊,不行不行,這直接丟棄了,記錄日志的任務不能直接丟棄。

        第四次測試

        這次又把書拿出來看了看,看了一些大牛寫的線程池構(gòu)造,最終敲定了這樣的構(gòu)造方式。

        private?static?ExecutorService?saveThreadPool?=?new?ThreadPoolExecutor(2,?40,?60L,?TimeUnit.SECONDS,
        ????????????new?LinkedBlockingQueue(50000),?Executors.defaultThreadFactory(),
        ????????????new?ThreadPoolExecutor.CallerRunsPolicy());

        采用LinkedBlockingQueue,最多可有50000個任務在阻塞隊列中,線程池最大值設置40個,核心池大小設置2個,多出來的38個線程最多活躍60秒就會被回收。

        拒絕采用CallerRunsPolicy,不會丟棄任務,只要線程池未關(guān)閉,該策略直接在調(diào)用者線程中,運行當前被丟棄的任務。顯然這樣做不會真的丟棄任務,但是,任務提交線程的性能極有可能會急劇下降。在代碼測試中,執(zhí)行了top,發(fā)現(xiàn)cpu的利用率穩(wěn)定在24%左右,這個可以接受測試結(jié)果:每秒鐘1千2,這個也遠遠超過了性能指標,而且日志也全都記錄到數(shù)據(jù)中,不過這個不是及時性的,它會在測試程序結(jié)束1分鐘后,才會完成數(shù)據(jù)如插入,這個和隊列任務有關(guān)。

        總結(jié):

        這個線程池我是沒有關(guān)閉的,因為每次任務提交后隊列中還有很多任務,如果關(guān)閉的話,每次在開啟一個線程池會降低速度,所以這個就不關(guān)閉了吧 如果有大神看出什么端倪的話,歡迎批評斧正,繼續(xù)優(yōu)化,個人感覺還有提升空間。

        最后

        線程池的知識在工作中還是比較重要的,所以還是有必要去掌握的,上面的方案應該還可以采用寫數(shù)據(jù)的時候可以考慮批量插入數(shù)據(jù)庫。這樣數(shù)據(jù)庫的吞吐量會大大提高,比如一次寫入5000條,不過這個可能會存在數(shù)據(jù)丟失,比如應用重啟的時候。不過對于日志來說的話,應該是允許丟失的,具體操作的話這個還是需要由不同的業(yè)務來決定。最后也推薦下以前寫的兩篇關(guān)于線程池的文章《【Java并發(fā)編程】面試必備之線程池》《【Java并發(fā)編程】從源碼分析幾道必問線程池的面試題?》

        往期精選

        最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)、等等。獲取方式:點“在看”,關(guān)注公眾號并回復 666?領取,更多內(nèi)容陸續(xù)奉上。

        文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

        謝謝支持喲 (*^__^*)

        瀏覽 80
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        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>
            日日嗨av一区二区三区免费 | 两个男人操一个女人视频 | 少妇高潮图片 | 插插操操| 无码日韩一区二区 | 国产老妇视频 | 做 视频免费观看网站 | 成人三级AV在线 | 欧美三级图片 | 亚洲欧美**制服 |