java線程池使用后到底要關(guān)閉嗎
線程池做什么
網(wǎng)絡(luò)請(qǐng)求通常有兩種形式:
第一種,請(qǐng)求不是很頻繁,而且每次連接后會(huì)保持相當(dāng)一段時(shí)間來(lái)讀數(shù)據(jù)或者寫(xiě)數(shù)據(jù),最后斷開(kāi),如文件下載,網(wǎng)絡(luò)流媒體等。
另一種形式是請(qǐng)求頻繁,但是連接上以后讀/寫(xiě)很少量的數(shù)據(jù)就斷開(kāi)連接??紤]到服務(wù)的并發(fā)問(wèn)題,如果每個(gè)請(qǐng)求來(lái)到以后服務(wù)都為它啟動(dòng)一個(gè)線程,那么這對(duì)服務(wù)的資源可能會(huì)造成很大的浪費(fèi),特別是第二種情況。
因?yàn)橥ǔG闆r下,創(chuàng)建線程是需要一定的耗時(shí)的,設(shè)這個(gè)時(shí)間為T(mén)1,而連接后讀/寫(xiě)服務(wù)的時(shí)間為T(mén)2,當(dāng)T1>>T2時(shí),我們就應(yīng)當(dāng)考慮一種策略或者機(jī)制來(lái)控制,使得服務(wù)對(duì)于第二種請(qǐng)求方式也能在較低的功耗下完成。
通常,我們可以用線程池來(lái)解決這個(gè)問(wèn)題,首先,在服務(wù)啟動(dòng)的時(shí)候,我們可以啟動(dòng)好幾個(gè)線程,并用一個(gè)容器(如線程池)來(lái)管理這些線程。
當(dāng)請(qǐng)求到來(lái)時(shí),可以從池中取一個(gè)線程出來(lái),執(zhí)行任務(wù)(通常是對(duì)請(qǐng)求的響應(yīng)),當(dāng)任務(wù)結(jié)束后,再將這個(gè)線程放入池中備用;
如果請(qǐng)求到來(lái)而池中沒(méi)有空閑的線程,該請(qǐng)求需要排隊(duì)等候。最后,當(dāng)服務(wù)關(guān)閉時(shí)銷毀該池即可。
然而最近在開(kāi)發(fā)中用到了java的線程池,然后就很疑惑這個(gè)線程池到底要不要手動(dòng)關(guān)閉,感覺(jué)是要關(guān)閉的,但是沒(méi)人強(qiáng)調(diào)線程池用完要關(guān)閉。so今天來(lái)試驗(yàn)下到底線程池用完要不要關(guān)閉。
直接上實(shí)驗(yàn)代碼
public static void main(String[] args) throws Exception { //用于獲取到本java進(jìn)程,進(jìn)而獲取總線程數(shù) RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); String jvmName = runtimeBean.getName(); System.out.println("JVM Name = " + jvmName); long pid = Long.valueOf(jvmName.split("@")[0]); System.out.println("JVM PID = " + pid); ThreadMXBean bean = ManagementFactory.getThreadMXBean(); int n = 30000; for (int i = 0; i < n; i++) { ThreadPoolExecutor executor = new ThreadPoolExecutor(10,20,1000,TimeUnit.SECONDS,new LinkedBlockingDeque<>()); for(int j=0;j<10;j++){ executor.execute(()->{ System.out.println("當(dāng)前線程總數(shù)為:"+bean.getThreadCount()); }); } } Thread.sleep(10000); System.out.println("線程總數(shù)為 = " + bean.getThreadCount()); }
簡(jiǎn)單來(lái)說(shuō)就是在一個(gè) for 循環(huán)中創(chuàng)建線程池,然后執(zhí)行一個(gè)打印任務(wù)(不執(zhí)行任務(wù)線程不會(huì)真正創(chuàng)建),打印出當(dāng)前 java 進(jìn)程的總線程數(shù),下面是打印部分結(jié)果:
線程
可以看到在創(chuàng)建到 15 萬(wàn)個(gè)線程是爆內(nèi)存,內(nèi)存占用百分百后 java 應(yīng)用崩潰。說(shuō)明線程未被回收。
PS:內(nèi)存占用百分百后,部分應(yīng)用開(kāi)始出現(xiàn)異常,界面花屏,閃屏,不能正常繪制gui,不知道為啥,即使后面內(nèi)存占用降下來(lái)也一樣,只能重啟應(yīng)用。
結(jié)論
使用完線程池一定記得回收,否則跑著跑著就內(nèi)存爆炸崩潰?;厥蘸瘮?shù)如下:
//執(zhí)行此函數(shù)后線程池不再接收新任務(wù),并等待所有任務(wù)執(zhí)行完畢后銷毀線程。此函數(shù)不會(huì)等待銷毀完畢 executor.shutdown(); //立即結(jié)束所有線程,不管是否正在運(yùn)行,返回未執(zhí)行完畢的任務(wù)列表 executor.shutdownNow();
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Java創(chuàng)建對(duì)象的六種常用方式總結(jié)
作為Java開(kāi)發(fā)者,經(jīng)常創(chuàng)建很多對(duì)象,你是否知道Java中創(chuàng)建對(duì)象有哪些方式呢?下面這篇文章主要給大家介紹了關(guān)于Java創(chuàng)建對(duì)象的六種常用方式,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06詳解如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API
作為后端程序員,我們的日常工作就是調(diào)用一些第三方服務(wù),將數(shù)據(jù)存入數(shù)據(jù)庫(kù),返回信息給前端。本文為大家介紹了如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API,需要的可以參考一下2022-12-12SpringBoot中自定義首頁(yè)(默認(rèn)頁(yè))及favicon的方法
這篇文章主要介紹了SpringBoot中如何自定義首頁(yè)(默認(rèn)頁(yè))及favicon,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08java微信開(kāi)發(fā)第二步 獲取消息和回復(fù)消息
這篇文章主要為大家分享java微信開(kāi)發(fā)的第二步,如何獲取消息和回復(fù)消息,感興趣的小伙伴們可以參考一下2016-05-05MyBatis多對(duì)多一對(duì)多關(guān)系查詢嵌套處理
這篇文章主要為大家介紹了MyBatis多對(duì)多一對(duì)多關(guān)系查詢嵌套處理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10