淺談Java四種線程池及new Thread的弊端
new Thread 的弊端
執(zhí)行異步任務(wù)只是如下 new Thread() 嗎?
new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start();
那你就太out了,new Thread的弊端如下:
1)每次通過new Thread()創(chuàng)建對(duì)象性能不佳。
2)線程缺乏統(tǒng)一管理,可能無限制新建線程,相互之間競(jìng)爭(zhēng),及可能占用過多系統(tǒng)資源導(dǎo)致死機(jī)或oom。
3)缺乏更多功能,如定時(shí)執(zhí)行、定期執(zhí)行、線程中斷。
相比new Thread,Java提供的四種線程池的好處在于:
1)重用存在的線程,減少對(duì)象創(chuàng)建、消亡的開銷,提升性能。
2)可有效控制最大并發(fā)線程數(shù),提高系統(tǒng)資源的使用率,同時(shí)避免過多資源競(jìng)爭(zhēng),避免堵塞。
3)提供定時(shí)執(zhí)行、定期執(zhí)行、單線程、并發(fā)數(shù)控制等功能。
Java 線程池
Java通過Executors提供四種線程池,分別為:
newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
newFixedThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待。
newScheduledThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行。
newSingleThreadExecutor 創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行。
Java里面線程池的頂級(jí)接口是Executor,但是嚴(yán)格意義上講Executor并不是一個(gè)線程池,而只是一個(gè)執(zhí)行線程的工具。真正的線程池接口是ExecutorService。下面這張圖完整描述了線程池的類體系結(jié)構(gòu):
1. newCachedThreadPool
創(chuàng)建一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線程的線程池,但是在以前構(gòu)造的線程可用時(shí)將重用它們。對(duì)于執(zhí)行很多短期異步任務(wù)的程序而言,這些線程池通??商岣叱绦蛐阅?。調(diào)用 execute 將重用以前構(gòu)造的線程(如果線程可用)。
如果現(xiàn)有線程沒有可用的,則創(chuàng)建一個(gè)新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。因此,長(zhǎng)時(shí)間保持空閑的線程池不會(huì)使用任何資源。
public static ExecutorService newCachedThreadPool()
示例代碼:
public class ThreadPoolExecutorTest { public static void main(String[] args ) { ExecutorService cacheThreadPool =Executors.newCachedThreadPool(); for(int i =1;i<=5;i++){ final int index=i ; try{ Thread.sleep(1000); }catch(InterruptedException e ) { e.printStackTrace(); } cacheThreadPool.execute(new Runnable(){ @Override public void run() { System.out.println("第" +index +"個(gè)線程" +Thread.currentThread().getName()); } }); } } }
//輸出結(jié)果
第1個(gè)線程pool-1-thread-1
第2個(gè)線程pool-1-thread-1
第3個(gè)線程pool-1-thread-1
第4個(gè)線程pool-1-thread-1 第5個(gè)線程pool-1-thread-1
由結(jié)果可看出 當(dāng)執(zhí)行第二個(gè)任務(wù)時(shí)第一個(gè)任務(wù)已經(jīng)完成,會(huì)復(fù)用執(zhí)行第一個(gè)任務(wù)的線程,而不用每次新建線程。
2. newFixedThreadPool
創(chuàng)建一個(gè)指定工作線程數(shù)量的線程池。每當(dāng)提交一個(gè)任務(wù)就創(chuàng)建一個(gè)工作線程,如果工作線程數(shù)量達(dá)到線程池初始的最大數(shù),則將提交的任務(wù)存入到池隊(duì)列中。
public static ExecutorService newFixedThreadPool(int nThreads)
nThreads - 池中的線程數(shù)
示例代碼:
public class ThreadPoolExecutorTest { public static void main(String[] args) { ExecutorService fixedThreadPool =Executors. newFixedThreadPool(3); for (int i =1; i<=5;i++){ final int index=i ; fixedThreadPool.execute(new Runnable(){ @Override public void run() { try { System.out.println("第" +index + "個(gè)線程" +Thread.currentThread().getName()); Thread.sleep(1000); } catch(InterruptedException e ) { e .printStackTrace(); } } }); } } }
由于設(shè)置最大線程數(shù)為3,所以在輸出三個(gè)數(shù)后等待2秒后才繼續(xù)輸出。
3. newScheduledThreadPool
創(chuàng)建一個(gè)線程池,它可安排在給定延遲后運(yùn)行命令或者定期地執(zhí)行。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
corePoolSize - 池中所保存的線程數(shù),即使線程是空閑的也包括在內(nèi)。
延遲執(zhí)行示例代碼:
public class ThreadPoolExecutorTest { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(3); scheduledThreadPool.schedule(newRunnable(){ @Override public void run() { System.out.println("延遲三秒"); } }, 3, TimeUnit.SECONDS); } }
表示延遲3秒執(zhí)行。
定期執(zhí)行示例代碼:
public class ThreadPoolExecutorTest { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(3); scheduledThreadPool.scheduleAtFixedRate(newRunnable(){ @Override public void run() { System.out.println("延遲1秒后每三秒執(zhí)行一次"); } },1,3,TimeUnit.SECONDS); } }
表示延遲1秒后每3秒執(zhí)行一次。
4.newSingleThreadExecutor
創(chuàng)建一個(gè)使用單個(gè) worker 線程的 Executor,以無界隊(duì)列方式來運(yùn)行該線程。(注意,如果因?yàn)樵陉P(guān)閉前的執(zhí)行期間出現(xiàn)失敗而終止了此單個(gè)線程,那么如果需要,一個(gè)新線程將代替它執(zhí)行后續(xù)的任務(wù))。可保證順序地執(zhí)行各個(gè)任務(wù),并且在任意給定的時(shí)間不會(huì)有多個(gè)線程是活動(dòng)的。與其他等效的 newFixedThreadPool(1)不同,可保證無需重新配置此方法所返回的執(zhí)行程序即可使用其他的線程。
public static ExecutorService newSingleThreadExecutor()
示例代碼:
public class ThreadPoolExecutorTest { public static void main(String[] args) { ExecutorService singleThreadPool= Executors.newSingleThreadExecutor(); for(int i=1;i<=5;i++){ int index=i; singleThreadPool.execute(new Runnable(){ @Override public void run() { try{ System.out.println("第"+index+"個(gè)線程"); Thread.sleep(2000); }catch(InterruptedException e) { e.printStackTrace(); } } }); } } }
到此這篇關(guān)于淺談Java四種線程池及new Thread的弊端的文章就介紹到這了,更多相關(guān)Java 線程池及new Thread內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用volatile關(guān)鍵字的注意事項(xiàng)
volatile關(guān)鍵字是Java中的一種稍弱的同步機(jī)制,為什么稱之為弱機(jī)制。這篇文章主要介紹了Java使用volatile關(guān)鍵字的注意事項(xiàng),需要的朋友可以參考下2017-02-02Eclipse+Java+Swing實(shí)現(xiàn)圖書管理系統(tǒng)(詳細(xì)代碼)
這篇文章主要介紹了Eclipse+Java+Swing實(shí)現(xiàn)圖書管理系統(tǒng)并附上詳細(xì)代碼,需要的小伙伴可以參考一下,希望對(duì)你有所幫助2022-01-01Java基于websocket協(xié)議與netty實(shí)時(shí)視頻彈幕交互實(shí)現(xiàn)
本文主要介紹了Java基于websocket協(xié)議與netty實(shí)時(shí)視頻彈幕交互實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Java關(guān)鍵字synchronized原理與鎖的狀態(tài)詳解
在Java當(dāng)中synchronized關(guān)鍵字通常是用來標(biāo)記一個(gè)方法或者代碼塊。本文將通過示例為大家詳細(xì)介紹一下Synchronized的各種使用方法,需要的可以參考一下2022-08-08java門禁系統(tǒng)面向?qū)ο蟪绦蛟O(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了java門禁系統(tǒng)面向?qū)ο蟪绦蛟O(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01