您好,登錄后才能下訂單哦!
一、如下方式存在的問題
new?Thread()?{ ????@Override ????public?void?run()?{ ????????//?業(yè)務(wù)邏輯 ????} }.start();
1、首先頻繁的創(chuàng)建、銷毀對象是一個很消耗性能的事情;
2、如果用戶量比較大,導(dǎo)致占用過多的資源,可能會導(dǎo)致我們的服務(wù)由于資源不足而宕機(jī);
3、綜上所述,在實際的開發(fā)中,這種操作其實是不可取的一種方式。
二、使用線程池有什么優(yōu)點
1、線程池中線程的使用率提升,減少對象的創(chuàng)建、銷毀;
2、線程池可以控制線程數(shù),有效的提升服務(wù)器的使用資源,避免由于資源不足而發(fā)生宕機(jī)等問題;
三、線程池的四種使用方式
1、newCachedThreadPool
創(chuàng)建一個線程池,如果線程池中的線程數(shù)量過大,它可以有效的回收多余的線程,如果線程數(shù)不足,那么它可以創(chuàng)建新的線程。
public?static?void?method()?throws?Exception?{ ????ExecutorService?executor?=?Executors.newCachedThreadPool(); ????for?(int?i?=?0;?i?<?5;?i++)?{ ????????final?int?index?=?i; ????????Thread.sleep(1000); ????????executor.execute(new?Runnable()?{ ????????????@Override ????????????public?void?run()?{ ????????????????System.out.println(Thread.currentThread().getName()?+?"??"?+?index); ????????????} ????????}); ????} }
執(zhí)行結(jié)果
通過分析我看可以看到,至始至終都由一個線程執(zhí)行,實現(xiàn)了線程的復(fù)用,并沒有創(chuàng)建多余的線程。
如果當(dāng)我們的業(yè)務(wù)需要一定的時間進(jìn)行處理,那么將會出現(xiàn)什么結(jié)果。我們來模擬一下。
可以明顯的看出,現(xiàn)在就需要幾條線程來交替執(zhí)行。
不足:這種方式雖然可以根據(jù)業(yè)務(wù)場景自動的擴(kuò)展線程數(shù)來處理我們的業(yè)務(wù),但是最多需要多少個線程同時處理缺是我們無法控制的;
優(yōu)點:如果當(dāng)?shù)诙€任務(wù)開始,第一個任務(wù)已經(jīng)執(zhí)行結(jié)束,那么第二個任務(wù)會復(fù)用第一個任務(wù)創(chuàng)建的線程,并不會重新創(chuàng)建新的線程,提高了線程的復(fù)用率;
2、newFixedThreadPool
這種方式可以指定線程池中的線程數(shù)。舉個栗子,如果一間澡堂子最大只能容納20個人同時洗澡,那么后面來的人只能在外面排隊等待。如果硬往里沖,那么只會出現(xiàn)一種情景,摩擦摩擦...
首先測試一下最大容量為一個線程,那么會不會是我們預(yù)測的結(jié)果。
public?static?void?method_01()?throws?InterruptedException?{ ????ExecutorService?executor?=?Executors.newFixedThreadPool(1); ????for?(int?i?=?0;?i?<?10;?i++)?{ ????????Thread.sleep(1000); ????????final?int?index?=?i; ????????executor.execute(()?->?{ ????????????try?{ ????????????????Thread.sleep(2?*?1000); ????????????}?catch?(InterruptedException?e)?{ ????????????????e.printStackTrace(); ????????????} ????????????System.out.println(Thread.currentThread().getName()?+?"??"?+?index); ????????}); ????} ????executor.shutdown(); }
執(zhí)行結(jié)果
我們改為3條線程再來看下結(jié)果
優(yōu)點:兩個結(jié)果綜合說明,newFixedThreadPool的線程數(shù)是可以進(jìn)行控制的,因此我們可以通過控制最大線程來使我們的服務(wù)器打到最大的使用率,同事又可以保證及時流量突然增大也不會占用服務(wù)器過多的資源。
3、newScheduledThreadPool
該線程池支持定時,以及周期性的任務(wù)執(zhí)行,我們可以延遲任務(wù)的執(zhí)行時間,也可以設(shè)置一個周期性的時間讓任務(wù)重復(fù)執(zhí)行。 該線程池中有以下兩種延遲的方法。
scheduleAtFixedRate
測試一
public?static?void?method_02()?{ ????ScheduledExecutorService?executor?=?Executors.newScheduledThreadPool(5); ????executor.scheduleAtFixedRate(new?Runnable()?{ ????????@Override ????????public?void?run()?{ ????????????long?start?=?new?Date().getTime(); ????????????System.out.println("scheduleAtFixedRate?開始執(zhí)行時間:"?+ ????????????????????DateFormat.getTimeInstance().format(new?Date())); ????????????try?{ ????????????????Thread.sleep(5000); ????????????}?catch?(InterruptedException?e)?{ ????????????????e.printStackTrace(); ????????????} ????????????long?end?=?new?Date().getTime(); ????????????System.out.println("scheduleAtFixedRate?執(zhí)行花費時間="?+?(end?-?start)?/?1000?+?"m"); ????????????System.out.println("scheduleAtFixedRate?執(zhí)行完成時間:"?+?DateFormat.getTimeInstance().format(new?Date())); ????????????System.out.println("======================================"); ????????} ????},?1,?5,?TimeUnit.SECONDS); }
執(zhí)行結(jié)果
測試二
總結(jié):以上兩種方式不同的地方是任務(wù)的執(zhí)行時間,如果間隔時間大于任務(wù)的執(zhí)行時間,任務(wù)不受執(zhí)行時間的影響。如果間隔時間小于任務(wù)的執(zhí)行時間,那么任務(wù)執(zhí)行結(jié)束之后,會立馬執(zhí)行,至此間隔時間就會被打亂。
scheduleWithFixedDelay
測試一
public?static?void?method_03()?{ ????ScheduledExecutorService?executor?=?Executors.newScheduledThreadPool(2); ????executor.scheduleWithFixedDelay(new?Runnable()?{ ????????@Override ????????public?void?run()?{ ????????????long?start?=?new?Date().getTime(); ????????????System.out.println("scheduleWithFixedDelay?開始執(zhí)行時間:"?+ ????????????????????DateFormat.getTimeInstance().format(new?Date())); ????????????try?{ ????????????????Thread.sleep(1000); ????????????}?catch?(InterruptedException?e)?{ ????????????????e.printStackTrace(); ????????????} ????????????long?end?=?new?Date().getTime(); ????????????System.out.println("scheduleWithFixedDelay執(zhí)行花費時間="?+?(end?-?start)?/?1000?+?"m"); ????????????System.out.println("scheduleWithFixedDelay執(zhí)行完成時間:" ????????????????????+?DateFormat.getTimeInstance().format(new?Date())); ????????????System.out.println("======================================"); ????????} ????},?1,?2,?TimeUnit.SECONDS); }
執(zhí)行結(jié)果
測試二
public?static?void?method_03()?{ ????ScheduledExecutorService?executor?=?Executors.newScheduledThreadPool(2); ????executor.scheduleWithFixedDelay(new?Runnable()?{ ????????@Override ????????public?void?run()?{ ????????????long?start?=?new?Date().getTime(); ????????????System.out.println("scheduleWithFixedDelay?開始執(zhí)行時間:"?+ ????????????????????DateFormat.getTimeInstance().format(new?Date())); ????????????try?{ ????????????????Thread.sleep(5000); ????????????}?catch?(InterruptedException?e)?{ ????????????????e.printStackTrace(); ????????????} ????????????long?end?=?new?Date().getTime(); ????????????System.out.println("scheduleWithFixedDelay執(zhí)行花費時間="?+?(end?-?start)?/?1000?+?"m"); ????????????System.out.println("scheduleWithFixedDelay執(zhí)行完成時間:" ????????????????????+?DateFormat.getTimeInstance().format(new?Date())); ????????????System.out.println("======================================"); ????????} ????},?1,?2,?TimeUnit.SECONDS); }
執(zhí)行結(jié)果
總結(jié):同樣的,跟scheduleWithFixedDelay測試方法一樣,可以測出scheduleWithFixedDelay的間隔時間不會受任務(wù)執(zhí)行時間長短的影響。
4、newSingleThreadExecutor
這是一個單線程池,至始至終都由一個線程來執(zhí)行。
public?static?void?method_04()?{ ????ExecutorService?executor?=?Executors.newSingleThreadExecutor(); ????for?(int?i?=?0;?i?<?5;?i++)?{ ????????final?int?index?=?i; ????????executor.execute(()?->?{ ????????????try?{ ????????????????Thread.sleep(2?*?1000); ????????????}?catch?(InterruptedException?e)?{ ????????????????e.printStackTrace(); ????????????} ????????????System.out.println(Thread.currentThread().getName()?+?"???"?+?index); ????????}); ????} ????executor.shutdown(); }
執(zhí)行結(jié)果
四、線程池的作用
線程池的作用主要是為了提升系統(tǒng)的性能以及使用率。文章剛開始就提到,如果我們使用最簡單的方式創(chuàng)建線程,如果用戶量比較大,那么就會產(chǎn)生很多創(chuàng)建和銷毀線程的動作,這會導(dǎo)致服務(wù)器在創(chuàng)建和銷毀線程上消耗的性能可能要比處理實際業(yè)務(wù)花費的時間和性能更多。線程池就是為了解決這種這種問題而出現(xiàn)的。
歡迎大家關(guān)注我的公種浩【程序員追風(fēng)】,文章都會在里面更新,整理的資料也會放在里面。
同樣思想的設(shè)計還有很多,比如數(shù)據(jù)庫連接池,由于頻繁的連接數(shù)據(jù)庫,然而創(chuàng)建連接是一個很消耗性能的事情,所有數(shù)據(jù)庫連接池就出現(xiàn)了。
最后
歡迎大家一起交流,喜歡文章記得點個贊喲,感謝支持!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。