日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

我会手动创建线程,为什么让我使用线程池?

發(fā)布時間:2025/3/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 我会手动创建线程,为什么让我使用线程池? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
  • 你有一個思想,我有一個思想,我們交換后,一個人就有兩個思想

  • If you can NOT explain it simply, you do NOT understand it well enough

現(xiàn)陸續(xù)將Demo代碼和技術(shù)文章整理在一起 Github實(shí)踐精選 ,方便大家閱讀查看,本文同樣收錄在此,覺得不錯,還請Star

上一篇文章 ?面試問我,創(chuàng)建多少個線程合適?我該怎么說??從定性到定量的分析了如何創(chuàng)建正確個數(shù)的線程來最大化利用系統(tǒng)資源(其實(shí)就是幾道小學(xué)數(shù)學(xué)題)。通常來講,有了個這個知識點(diǎn)傍身,按需手動創(chuàng)建相應(yīng)個數(shù)的線程就好

但是現(xiàn)實(shí)中,你也許聽過或者被要求:

盡量避免手動創(chuàng)建線程,應(yīng)使用線程池統(tǒng)一管理線程

為什么會有這樣的要求?背后的道理又是怎樣的呢?順著這個經(jīng)驗理論來推斷,那肯定是手動創(chuàng)建線程有缺點(diǎn)

手動創(chuàng)建線程有什么缺點(diǎn)?

  • 不受控風(fēng)險

  • 頻繁創(chuàng)建開銷大

  • 不受控風(fēng)險

    這個缺點(diǎn),相信你也可以說出一二

    系統(tǒng)資源有限,每個人針對不同業(yè)務(wù)都可以手動創(chuàng)建線程,并且創(chuàng)建標(biāo)準(zhǔn)不一樣(比如線程沒有名字)。當(dāng)系統(tǒng)運(yùn)行起來,所有線程都在瘋狂搶占資源,無組織無紀(jì)律,混亂場面可想而知(出現(xiàn)問題,自然也就不可能輕易的發(fā)現(xiàn)和解決)

    如果有位神奇的小伙伴,為每個請求都創(chuàng)建一個線程,當(dāng)大量請求鋪面而來的時候,這好比一個正規(guī)木馬程序,內(nèi)存被無情榨干耗盡(你無情,你冷酷,你無理取鬧)

    另外,過多的線程自然也會引起上下文切換的開銷

    總的來說,不受控風(fēng)險很大

    頻繁創(chuàng)建開銷大

    面試問:頻繁手動創(chuàng)建線程有什么問題?

    答:開銷大

    這貌似是一個不假思索就可以回答出來的正確答案。那我要繼續(xù)問了

    面試官:創(chuàng)建一個線程干了什么就開銷大了?和我們創(chuàng)建一個普通 Java 對象有什么差別?

    答:... 嗯...啊

    按照常規(guī)理解 new Thread() 創(chuàng)建一個線程和 new Object() 沒有什么差別。Java中萬物接對象,因為 Thread 的老祖宗也是 Object

    如果你真是這么理解的,說明你對線程的生命周期還不是很理解,請回看之前的?Java線程生命周期這樣理解挺簡單的

    在這篇文章中我們明確說明,new Thread() 在操作系統(tǒng)層面并沒有創(chuàng)建新的線程,這是編程語言特有的。真正轉(zhuǎn)換為操作系統(tǒng)層面創(chuàng)建一個線程,還要調(diào)用操作系統(tǒng)內(nèi)核的API,然后操作系統(tǒng)要為該線程分配一系列的資源

    廢話不多說,我們將二者做個對比:

    new Object() 過程

    Object?obj?=?new?Object();

    當(dāng)我需要【對象】時,我就會給自己 new 一個(不知你是否和我一樣),這個過程你應(yīng)該很熟悉了:

  • 分配一塊內(nèi)存 M

  • 在內(nèi)存 M 上初始化該對象

  • 將內(nèi)存 M 的地址賦值給引用變量 obj

  • 就是這么簡單

    創(chuàng)建一個線程的過程

    上面已經(jīng)提到了,創(chuàng)建一個線程還要調(diào)用操作系統(tǒng)內(nèi)核API。為了更好的理解創(chuàng)建并啟動一個線程的開銷,我們需要看看 JVM 在背后幫我們做了哪些事情:

  • 它為一個線程棧分配內(nèi)存,該棧為每個線程方法調(diào)用保存一個棧幀

  • 每一棧幀由一個局部變量數(shù)組、返回值、操作數(shù)堆棧和常量池組成

  • 一些支持本機(jī)方法的 jvm 也會分配一個本機(jī)堆棧

  • 每個線程獲得一個程序計數(shù)器,告訴它當(dāng)前處理器執(zhí)行的指令是什么

  • 系統(tǒng)創(chuàng)建一個與Java線程對應(yīng)的本機(jī)線程

  • 將與線程相關(guān)的描述符添加到JVM內(nèi)部數(shù)據(jù)結(jié)構(gòu)中

  • 線程共享堆和方法區(qū)域

  • 這段描述稍稍有點(diǎn)抽象,用數(shù)據(jù)來說明創(chuàng)建一個線程(即便不干什么)需要多大空間呢?答案是大約 ?1M??左右

    java?-XX:+UnlockDiagnosticVMOptions?-XX:NativeMemoryTracking=summary?-XX:+PrintNMTStatistics?-version

    上圖是我用 Java8 的測試結(jié)果,19個線程,預(yù)留和提交的大概都是19000+KB,平均每個線程大概需要 1M 左右的大小(Java11的結(jié)果完全不同,這個大家自行測試吧)

    相信到這里你已經(jīng)明白了,對于性能要求嚴(yán)苛的現(xiàn)在,頻繁手動創(chuàng)建/銷毀線程的代價是非常巨大的,解決方案自然也是你知道的線程池了

    什么是線程池?

    你常見的數(shù)據(jù)庫連接池,實(shí)例池,還有XX池,OO池,各種池,都是一種池化(pooling)思想,簡而言之就是為了最大化收益,并最小化風(fēng)險,將資源統(tǒng)一在一起管理的思想

    Java 也提供了它自己實(shí)現(xiàn)的線程池模型——?ThreadPoolExecutor。套用上面池化的想象來說,Java線程池就是為了最大化高并發(fā)帶來的性能提升,并最小化手動創(chuàng)建線程的風(fēng)險,將多個線程統(tǒng)一在一起管理的思想

    為了了解這個管理思想,我們當(dāng)前只需要關(guān)注?ThreadPoolExecutor?構(gòu)造方法就可以了

    public?ThreadPoolExecutor(int?corePoolSize,int?maximumPoolSize,long?keepAliveTime,TimeUnit?unit,BlockingQueue<Runnable>?workQueue,ThreadFactory?threadFactory,RejectedExecutionHandler?handler)?{if?(corePoolSize?<?0?||maximumPoolSize?<=?0?||maximumPoolSize?<?corePoolSize?||keepAliveTime?<?0)throw?new?IllegalArgumentException();if?(workQueue?==?null?||?threadFactory?==?null?||?handler?==?null)throw?new?NullPointerException();this.acc?=?System.getSecurityManager()?==?null??null?:AccessController.getContext();this.corePoolSize?=?corePoolSize;this.maximumPoolSize?=?maximumPoolSize;this.workQueue?=?workQueue;this.keepAliveTime?=?unit.toNanos(keepAliveTime);this.threadFactory?=?threadFactory;this.handler?=?handler; }

    這么復(fù)雜的構(gòu)造方法在JDK中還真是不多見,為了個更形象化的讓大家理解這幾個核心參數(shù),我們以多數(shù)人都經(jīng)歷過的春運(yùn)(北京——上海)來說明(表格有變動,請閱讀原文)

    序號參數(shù)名稱參數(shù)解釋春運(yùn)形象說明
    1corePoolSize表示常駐核心線程數(shù),如果大于0,即使本地任務(wù)執(zhí)行完也不會被銷毀日常固定的列車數(shù)輛(不管是不是春運(yùn),都要有固定這些車次運(yùn)行)
    2maximumPoolSize表示線程池能夠容納可同時執(zhí)行的最大線程數(shù)春運(yùn)客流量大,臨時加車,加車后,總列車次數(shù)不能超過這個最大值,否則就會出現(xiàn)調(diào)度不開等問題
    3keepAliveTime表示線程池中線程空閑的時間,當(dāng)空閑時間達(dá)到該值時,線程會被銷毀,只剩下?corePoolSize?個線程位置春運(yùn)壓力過后,臨時的加車(如果空閑時間超過keepAliveTime)就會被撤掉,只保留日常固定的列車車次數(shù)量用于日常運(yùn)營
    4unitkeepAliveTime?的時間單位,最終都會轉(zhuǎn)換成【納秒】,因為CPU的執(zhí)行速度杠杠滴keepAliveTime?的單位,春運(yùn)以【天】為計算單位
    5workQueue當(dāng)請求的線程數(shù)大于?maximumPoolSize?時,線程進(jìn)入該阻塞隊列春運(yùn)壓力異常大,即便加車后(達(dá)到maximumPoolSize)也不能滿足要求,所有乘坐請求都會進(jìn)入該阻塞隊列中排隊
    6threadFactory顧名思義,線程工廠,用來生產(chǎn)一組相同任務(wù)的線程,同時也可以通過它增加前綴名,虛擬機(jī)棧分析時更清晰比如(北京——上海)就屬于該段列車所有前綴,表明列車運(yùn)輸職責(zé)
    7handler執(zhí)行拒絕策略,當(dāng)?workQueue?達(dá)到上限,就要通過這個來處理,比如拒絕,丟棄等,這是一種限流的保護(hù)措施當(dāng)workQueue排隊也達(dá)到隊列最大上線,就要提示無票等拒絕策略了,因為我們不能加車了,當(dāng)前所有車次已經(jīng)滿負(fù)載

    試想,如果有請求就新建一趟列車,請求結(jié)束就“銷毀”這趟列車,頻繁往復(fù)這樣操作,這樣的代價肯定是不能接受的。

    可以看到,使用線程池不但能完成手動創(chuàng)建線程可以做到的工作,同時也填補(bǔ)了手動線程不能做到的空白。歸納起來說,線程池的作用包括:

  • 利用線程池管理并服用線程,控制最大并發(fā)數(shù)(手動創(chuàng)建線程很難得到保證)

  • 實(shí)現(xiàn)任務(wù)線程隊列緩存策略和拒絕機(jī)制

  • 實(shí)現(xiàn)某些與實(shí)踐相關(guān)的功能,如定時執(zhí)行,周期執(zhí)行等(比如列車指定時間運(yùn)行)

  • 隔離線程環(huán)境,比如,交易服務(wù)和搜索服務(wù)在同一臺服務(wù)器上,分別開啟兩個線程池,交易線程的資源消耗明顯要大。因此,通過配置獨(dú)立的線程池,將較慢的交易服務(wù)與搜索服務(wù)個離開,避免個服務(wù)線程互相影響

  • 相信到這里,你已經(jīng)了解線程池的基本思想了,在使用過程中還是有幾個注意事項要說明一下的

    線程池使用思想/注意事項

    不能忽略的線程池拒絕策略

    我們很難準(zhǔn)確的預(yù)測未來的最大并發(fā)量,所以定制合理的拒絕策略是必不可少的步驟。默認(rèn)情況, ThreadPoolExecutor 提供了四種拒絕策略:

  • AbortPolicy:默認(rèn)的拒絕策略,會 throw RejectedExecutionException 拒絕

  • CallerRunsPolicy:提交任務(wù)的線程自己去執(zhí)行該任務(wù)

  • DiscardOldestPolicy:丟棄最老的任務(wù),其實(shí)就是把最早進(jìn)入工作隊列的任務(wù)丟棄,然后把新任務(wù)加入到工作隊列

  • DiscardPolicy:相當(dāng)大膽的策略,直接丟棄任務(wù),沒有任何異常拋出

  • 不同的框架(Netty,Dubbo)都有不同的拒絕策略,我們也可以通過實(shí)現(xiàn)?RejectedExecutionHandler?自定義的拒絕策略

    對于采用何種策略,具體要看執(zhí)行的任務(wù)重要程度。如果是一些不重要任務(wù),可以選擇直接丟棄;如果是重要任務(wù),可以采用降級(所謂降級就是在服務(wù)無法正常提供功能的情況下,采取的補(bǔ)救措施。具體采用何種降級手段,這也是要看具體場景)處理,例如將任務(wù)信息插入數(shù)據(jù)庫或者消息隊列,啟用一個專門用作補(bǔ)償?shù)木€程池去進(jìn)行補(bǔ)償

    沒有絕對的拒絕策略,只有適合那一個,但在設(shè)計過程中千萬不要忽略掉拒絕策略就可以

    禁止使用Executors創(chuàng)建線程池

    相信很多人都看到過這個問題(阿里巴巴Java開發(fā)手冊說明禁止使用 Executors 創(chuàng)建線程池),我把出處(P247)截圖在此:

    Executors 大大的簡化了我們創(chuàng)建各種類型線程池的方式,為什么還不讓使用呢?

    其實(shí),只要你打開看看它的靜態(tài)方法參數(shù)就會明白了

    傳入的workQueue 是一個邊界為?Integer.MAX_VALUE?隊列,我們也可以變相的稱之為無界隊列了,因為邊界太大了,這么大的等待隊列也是非常消耗內(nèi)存的

    /***?Creates?a?{@code?LinkedBlockingQueue}?with?a?capacity?of*?{@link?Integer#MAX_VALUE}.*/ public?LinkedBlockingQueue()?{this(Integer.MAX_VALUE); }

    另外該 ThreadPoolExecutor方法使用的是默認(rèn)拒絕策略(直接拒絕),但并不是所有業(yè)務(wù)場景都適合使用這個策略,當(dāng)很重要的請求過來直接選擇拒絕顯然是不合適的

    總的來說,使用 Executors 創(chuàng)建的線程池太過于理想化,并不能滿足很多現(xiàn)實(shí)中的業(yè)務(wù)場景,所以要求我們通過 ThreadPoolExecutor來創(chuàng)建,并傳入合適的參數(shù)

    總結(jié)

    當(dāng)我們需要頻繁的創(chuàng)建線程時,我們要考慮到通過線程池統(tǒng)一管理線程資源,避免不可控風(fēng)險以及額外的開銷

    了解了線程池的幾個核心參數(shù)概念后,我們也需要經(jīng)過調(diào)優(yōu)的過程來設(shè)置最佳線程參數(shù)值(這個過程時必不可少的)

    線程池雖然彌補(bǔ)了手動創(chuàng)建線程的缺陷和空白,同時,合理的降級策略能大大增加系統(tǒng)的穩(wěn)定性

    阿里巴巴手冊都是前輩們無數(shù)填坑后總結(jié)的精華,你也應(yīng)該遵守相應(yīng)的指示,結(jié)合自己的實(shí)際業(yè)務(wù)場景,設(shè)定合適的參數(shù)來創(chuàng)建線程池

    靈魂追問

  • 我們說了這么多線程池的好,那使用線程池有哪些缺點(diǎn)或限制呢?

  • 為什么不建議所有業(yè)務(wù)共用一個線程池?有什么缺點(diǎn)?

  • 給線程池設(shè)置指定前綴,有哪些方式?

  • 總結(jié)

    以上是生活随笔為你收集整理的我会手动创建线程,为什么让我使用线程池?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲熟女乱色一区二区三区久久久 | 字幕网在线观看 | 中文字幕在线观 | 国产人妻777人伦精品hd | 小婕子伦流澡到高潮h | 亚洲成年| 91精品国产乱码久久久久久久久 | 永久免费看片在线观看 | 天天操天天干天天 | 91视频一区 | 欧美色综合网站 | 折磨小男生性器羞耻的故事 | 亚洲艹 | 超碰97人 | 欧洲视频在线观看 | 国产精品电影一区二区 | av字幕网 | 欧美日韩三级视频 | 婷婷亚洲精品 | 人人妻人人爽欧美成人一区 | 亚洲一区二区三区在线观看视频 | 日韩av网址大全 | 日本夫妻性生活视频 | 午夜精品福利电影 | 女人私密又肥又大 | 日韩在线视频观看免费 | 日韩极品在线观看 | 国产精品社区 | 高跟丝袜av | 日韩欧美综合 | 亚洲h网站| 国产精品19乱码一区二区三区 | 国产精品久久久久久白浆 | 天天摸天天摸 | 国产午夜精品福利视频 | 黄页av | 超碰免费人人 | 激情播播网 | 国产国产国产 | 日日草视频 | 污污视频网站在线免费观看 | 欧美成人一区在线观看 | 毛利兰被扒开腿做同人漫画 | 国产电影免费观看高清完整版视频 | 韩国三级hd中文字幕 | 久久久久成人精品无码中文字幕 | 91久久人人 | jjzz黄色片| 黄色aaa毛片| 国产欧美精品一区二区在线播放 | 日韩欧美在线精品 | 久久好色| 丝袜老师扒开让我了一夜漫画 | 天堂…中文在线最新版在线 | 四虎国产精品成人免费入口 | 成年人理论片 | 91福利在线导航 | 娇妻高潮浓精白浆xxⅹ | 99热国| 亚洲一区二区三区麻豆 | 思思久久久 | 久久精品123 | 色婷婷aⅴ| 欧美黄色一级片视频 | 国产日韩大片 | 国产探花一区二区 | 国产不卡在线播放 | 国产精品无码成人网站视频 | 三日本三级少妇三级99 | 涩涩视频免费 | 欧美激情久久久久 | 国产精品一区在线 | 911毛片 | 色哟哟黄色 | 免费在线看黄网站 | 日本成人免费观看 | 黄色喷水视频 | 波多野结衣潜藏淫欲 | 麻豆一区二区三区在线观看 | 婷婷深爱五月 | 67194成人 | 国产极品美女在线 | 精品无码一区二区三区在线 | 美女裸体跪姿扒开屁股无内裤 | 性高潮久久久久久久久久 | 男女啪啪软件 | aaa一区二区 | 日本一区二区在线免费观看 | 国产porn| 国产51自产区 | 在线中文字幕播放 | 97超视频| √8天堂资源地址中文在线 欧美精品在线一区二区 | 中文字幕色片 | 人妻巨大乳一二三区 | 黄色三级免费网站 | 国产青青青 | 国产男男gay | 日韩精品视频免费看 |