這篇文章將為大家詳細講解有關java的線程池原理是什么,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
成都創(chuàng)新互聯(lián)始終堅持【策劃先行,效果至上】的經營理念,通過多達十載累計超上千家客戶的網(wǎng)站建設總結了一套系統(tǒng)有效的推廣解決方案,現(xiàn)已廣泛運用于各行各業(yè)的客戶,其中包括:三輪攪拌車等企業(yè),備受客戶贊美。
在之前已經使用過線程池了。在使用中,基本上就是初始化好線程池的實例之后,把任務丟進去,等待調度執(zhí)行就可以了。使用起來非常簡單方便。
每次new Thread新建對象,性能差
線程缺乏統(tǒng)一管理,可能無限制的新建線程,相互競爭,有可能占用過多系統(tǒng)資源導致死機或者OOM
缺少更多功能,如更多執(zhí)行、定期執(zhí)行、線程中斷
重用存在的線程,減少對象創(chuàng)建、消亡的開銷,性能好
可以有效控制最大并發(fā)線程數(shù),提高系統(tǒng)資源利用率,同時可以避免過多資源競爭,避免阻塞
提供定時執(zhí)行、定期執(zhí)行、單線程、并發(fā)數(shù)控制等高級功能
參數(shù):
corePoolSize:核心線程數(shù)量。建議和cpu的核心數(shù)差不多,當有任務提交,檢測當前線程池內的線程數(shù)小于corePoolSize的話,新建線程執(zhí)行任務,而不會開始復用,會新建,直到達到corePoolSize。線程池內的線程數(shù)大于等于corePoolSize時,將任務放入workQueue等待。
maximumPoolSize:允許線程池內最大線程數(shù)。當隊列滿了之后,如果線程池內的線程數(shù)小于maximumPoolSize則新建線程,如果大于等于執(zhí)行拒絕策略。
如果maximumPoolSize是30,corePoolSize是10,當隊列滿了后只能再開20個線程。
workQueue:阻塞隊列,存儲等待執(zhí)行的任務,很重要,會對線程池運行過程產生重大影響
keepAliveTime:線程沒有任務執(zhí)行時最多保持多久時間終止。線程池維護線程所允許的空閑時間。當線程池中的線程數(shù)量大于CorePoolSize時,如果這是沒有新的任務提交,線程會等待,直到時間超過keepAliveTime才銷毀。
unit:keepAliveTime的時間單位
threadFactory:線程工廠,用來創(chuàng)建線程,會有一個默認的工廠來創(chuàng)建線程。使用默認的工廠創(chuàng)建線程時,線程擁有相同的優(yōu)先級,并且是非守護的線程,同時也設置了線程的名稱。
rejectHandle:當拒絕處理任務時的策略。如果workQueue阻塞隊列滿了,并且沒有空閑的線程時,這時還繼續(xù)提交任務,我們就需要一種策略來處理這個任務。線程池總共提供了四種策略:
直接拋出異常,默認策略
用調用者所在的線程執(zhí)行任務
丟棄隊列中最靠前的任務,并執(zhí)行當前任務
直接丟棄這個任務
如果運行的線程數(shù)小于CorePoolSize時,直接創(chuàng)建新線程創(chuàng)建任務,即使線程池中的其他線程是空閑的。
如果線程池中的線程數(shù)量大于等于CorePoolSize且小于maximumPoolSize時,則只有當wokQueue滿時才創(chuàng)建新的線程去處理任務。
如果我們設置CorePoolSize與maximumPoolSize相等,那么創(chuàng)建的線程池大小是固定的,這時如果有新任務提交且workQueue還沒滿,就把請求放入workQueue中,等待空閑線程從workQueue中取任務進行處理。
如果運行的線程數(shù)量大于maximumPoolSize時,這時如果workQueue滿,那么會通過一個拒絕策略參數(shù)來指定策略處理任務。
如果我們想降低系統(tǒng)資源的消耗,包括CPU的使用率、操作系統(tǒng)資源的消耗,可以設置一個較大的workQueue容量和較小的CorePoolSize容量,這樣會降低線程處理的吞吐量。如果我們提交的任務經常發(fā)生阻塞,我們可以設置maximumPoolSize來設置線程池容量。如果我們隊列容量較小,通常需要把maximumPoolSize設置大一些,這樣CPU使用率會高一些。但是如果線程池容量設置過大,在提交人物數(shù)量過多的情況下,并發(fā)量會增加,那么線程間資源調度就是一個需要考慮的問題,反而會降低處理的吞吐量。
當我們初始化一個線程池之后,通常有上面幾種狀態(tài)。
running:可以接受新提交的任務,也能處理阻塞隊列中的任務。
shutdown:關閉狀態(tài),當一個線程池實例處于shutdown狀態(tài)時,不能再接收新提交的任務,但卻可以繼續(xù)處理阻塞隊列中已經保存的任務。
stop:也不能接收新的任務,也不處理隊列中的任務。會中斷正在處理的線程任務。
tidying:所有任務都已經終止了,沒有活動中的線程。當線程池進行該狀態(tài)時候,會執(zhí)行鉤子方法terminated() 。
execute():提交任務,交給線程池執(zhí)行
submit():提交任務,能夠返回執(zhí)行結果 相當于execute+Future
shutdown():關閉線程池,等待任務都執(zhí)行完
shutdownNow():關閉線程池,不等待任務執(zhí)行完
getTaskCount():線程池已執(zhí)行和未執(zhí)行的任務總數(shù)
getCompletedTaskCount():已完成的任務數(shù)量
getPoolSize():線程池當前的線程數(shù)量
getActiveCount():當前線程池中正在執(zhí)行任務的線程數(shù)量
Executors.newCachedThreadPool:創(chuàng)建一個可緩存的線程池,如果線程池的長度超過了線程的需要,可以靈活回收空閑線程,如果沒有回收的,可以新建線程
Executors.newFixedThreadPool:創(chuàng)建一個定長的線程池,可以控制線程的最大并發(fā)數(shù),超出的線程會在隊列中等待
Executors.newScheduledThreadPool:也是創(chuàng)建一個定長的線程池。支持定時以及周期性的任務執(zhí)行。
Executors.newSingleThreadExecutor:創(chuàng)建一個單線程的線程池,會用唯一的工作線程來執(zhí)行任務。保證所有任務按照指定順序去執(zhí)行(先入先出等)。
Executors.newCachedThreadPool示例代碼:
@Slf4j public class ThreadPoolExample1 { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i< 10; i++){ final int index = i; executorService.execute(new Runnable() { @Override public void run() { log.info("task:{}", index); } }); } //一定要關閉線程池,否則程序不結束 executorService.shutdown(); } }
Executors.newSingleThreadExecutor示例代碼:
@Slf4j public class ThreadPoolExample3 { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i< 10; i++){ final int index = i; executorService.execute(new Runnable() { @Override public void run() { log.info("task:{}", index); } }); } //一定要關閉線程池,否則程序不結束 executorService.shutdown(); } }
輸出結果:
17:08:16.870 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:0 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:1 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:2 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:3 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:4 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:5 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:6 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:7 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:8 17:08:16.875 [pool-1-thread-1] INFO com.vincent.example.threadPool.ThreadPoolExample3 - task:9
相當于單線程按順序執(zhí)行。
Executors.newScheduledThreadPool代碼示例:
@Slf4j public class ThreadPoolExample4 { public static void main(String[] args) { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { log.warn("schedule run"); } },1, 3, TimeUnit.SECONDS); //這里不需要關閉線程池 //scheduledExecutorService.shutdown(); } }
上面目的是:延遲1秒后,每個三秒執(zhí)行一次任務,由于這個任務時不定的執(zhí)行,因此這里不應該關閉線程池。如果需要關閉線程池的話,可以設置一個觸發(fā)條件來關閉。類似于Timer類:
@Slf4j public class ThreadPoolExample4 { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { log.warn("timer run"); } }, new Date(), 5*1000); } }
CPU密集型任務,就需要盡量壓榨CPU,參考值可以設置為NCPU+1
如果是IO密集型任務,參考值可以設置為2*NCPU
我們只用線程池主要是為了重用存在的線程,減少對象創(chuàng)建消亡,能有效控制最大線程并發(fā)數(shù),可以避免過多的資源競爭和阻塞,也可以定時執(zhí)行單線程與控制線程的執(zhí)行性能比較好。 這不代表線程池應該隨時隨地用,一定要根據(jù)自己的實際場景來分析使用參數(shù)配置
關于java的線程池原理是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
名稱欄目:java的線程池原理是什么
路徑分享:http://jinyejixie.com/article34/iisdse.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)頁設計公司、網(wǎng)站策劃、用戶體驗、App設計、微信公眾號、全網(wǎng)營銷推廣
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)