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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

java高并发(十八)线程池

發(fā)布時間:2024/9/16 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java高并发(十八)线程池 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? 在之前已經(jīng)使用過線程池了。在使用中,基本上就是初始化好線程池的實例之后,把任務(wù)丟進(jìn)去,等待調(diào)度執(zhí)行就可以了。使用起來非常簡單方便。

new Thread弊端

  • 每次new Thread新建對象,性能差
  • 線程缺乏統(tǒng)一管理,可能無限制的新建線程,相互競爭,有可能占用過多系統(tǒng)資源導(dǎo)致死機或者OOM
  • 缺少更多功能,如更多執(zhí)行、定期執(zhí)行、線程中斷

線程池的好處

  • 重用存在的線程,減少對象創(chuàng)建、消亡的開銷,性能好
  • 可以有效控制最大并發(fā)線程數(shù),提高系統(tǒng)資源利用率,同時可以避免過多資源競爭,避免阻塞
  • 提供定時執(zhí)行、定期執(zhí)行、單線程、并發(fā)數(shù)控制等高級功能

ThreadPoolExecutor

參數(shù):

  • corePoolSize:核心線程數(shù)量。建議和cpu的核心數(shù)差不多,當(dāng)有任務(wù)提交,檢測當(dāng)前線程池內(nèi)的線程數(shù)小于corePoolSize的話,新建線程執(zhí)行任務(wù),而不會開始復(fù)用,會新建,直到達(dá)到corePoolSize。線程池內(nèi)的線程數(shù)大于等于corePoolSize時,將任務(wù)放入workQueue等待。
  • maximumPoolSize:允許線程池內(nèi)最大線程數(shù)。當(dāng)隊列滿了之后,如果線程池內(nèi)的線程數(shù)小于maximumPoolSize則新建線程,如果大于等于執(zhí)行拒絕策略。
    如果maximumPoolSize是30,corePoolSize是10,當(dāng)隊列滿了后只能再開20個線程。
  • workQueue:阻塞隊列,存儲等待執(zhí)行的任務(wù),很重要,會對線程池運行過程產(chǎn)生重大影響
  • keepAliveTime:線程沒有任務(wù)執(zhí)行時最多保持多久時間終止。線程池維護(hù)線程所允許的空閑時間。當(dāng)線程池中的線程數(shù)量大于CorePoolSize時,如果這時沒有新的任務(wù)提交,線程會等待,直到時間超過keepAliveTime才銷毀。
  • unit:keepAliveTime的時間單位
  • threadFactory:線程工廠,用來創(chuàng)建線程,會有一個默認(rèn)的工廠來創(chuàng)建線程。使用默認(rèn)的工廠創(chuàng)建線程時,線程擁有相同的優(yōu)先級,并且是非守護(hù)的線程,同時也設(shè)置了線程的名稱。
  • rejectHandle:當(dāng)拒絕處理任務(wù)時的策略。如果workQueue阻塞隊列滿了,并且沒有空閑的線程時,這時還繼續(xù)提交任務(wù),我們就需要一種策略來處理這個任務(wù)。線程池總共提供了四種策略:
  • 直接拋出異常,默認(rèn)策略
  • ?用調(diào)用者所在的線程執(zhí)行任務(wù)
  • 丟棄隊列中最靠前的任務(wù),并執(zhí)行當(dāng)前任務(wù)
  • 直接丟棄這個任務(wù)

????如果運行的線程數(shù)小于CorePoolSize時,直接創(chuàng)建新線程創(chuàng)建任務(wù),即使線程池中的其他線程是空閑的。

????如果線程池中的線程數(shù)量大于等于CorePoolSize且小于maximumPoolSize時,則只有當(dāng)wokQueue滿時才創(chuàng)建新的線程去處理任務(wù)。

????如果我們設(shè)置CorePoolSize與maximumPoolSize相等,那么創(chuàng)建的線程池大小是固定的,這時如果有新任務(wù)提交且workQueue還沒滿,就把請求放入workQueue中,等待空閑線程從workQueue中取任務(wù)進(jìn)行處理。

? ? 如果運行的線程數(shù)量大于maximumPoolSize時,這時如果workQueue滿,那么會通過一個拒絕策略參數(shù)來指定策略處理任務(wù)。

? ? 如果我們想降低系統(tǒng)資源的消耗,包括CPU的使用率、操作系統(tǒng)資源的消耗,可以設(shè)置一個較大的workQueue容量和較小的CorePoolSize容量,這樣會降低線程處理的吞吐量。如果我們提交的任務(wù)經(jīng)常發(fā)生阻塞,我們可以設(shè)置maximumPoolSize來設(shè)置線程池容量。如果我們隊列容量較小,通常需要把maximumPoolSize設(shè)置大一些,這樣CPU使用率會高一些。但是如果線程池容量設(shè)置過大,在提交人物數(shù)量過多的情況下,并發(fā)量會增加,那么線程間資源調(diào)度就是一個需要考慮的問題,反而會降低處理的吞吐量。

線程池狀態(tài)

當(dāng)我們初始化一個線程池之后,通常有上面幾種狀態(tài)。

running:可以接受新提交的任務(wù),也能處理阻塞隊列中的任務(wù)。

shutdown:關(guān)閉狀態(tài),當(dāng)一個線程池實例處于shutdown狀態(tài)時,不能再接收新提交的任務(wù),但卻可以繼續(xù)處理阻塞隊列中已經(jīng)保存的任務(wù)。

stop:也不能接收新的任務(wù),也不處理隊列中的任務(wù)。會中斷正在處理的線程任務(wù)。

tidying:所有任務(wù)都已經(jīng)終止了,沒有活動中的線程。當(dāng)線程池進(jìn)行該狀態(tài)時候,會執(zhí)行鉤子方法terminated() 。

ThreadPoolExecutor中的方法

  • execute():提交任務(wù),交給線程池執(zhí)行
  • submit():提交任務(wù),能夠返回執(zhí)行結(jié)果 相當(dāng)于execute+Future
  • shutdown():關(guān)閉線程池,等待任務(wù)都執(zhí)行完
  • shutdownNow():關(guān)閉線程池,不等待任務(wù)執(zhí)行完
  • getTaskCount():線程池已執(zhí)行和未執(zhí)行的任務(wù)總數(shù)
  • getCompletedTaskCount():已完成的任務(wù)數(shù)量
  • getPoolSize():線程池當(dāng)前的線程數(shù)量
  • getActiveCount():當(dāng)前線程池中正在執(zhí)行任務(wù)的線程數(shù)量
  • Executors框架接口

    • Executors.newCachedThreadPool:創(chuàng)建一個可緩存的線程池,如果線程池的長度超過了線程的需要,可以靈活回收空閑線程,如果沒有回收的,可以新建線程
    • Executors.newFixedThreadPool:創(chuàng)建一個定長的線程池,可以控制線程的最大并發(fā)數(shù),超出的線程會在隊列中等待
    • Executors.newScheduledThreadPool:也是創(chuàng)建一個定長的線程池。支持定時以及周期性的任務(wù)執(zhí)行。
    • Executors.newSingleThreadExecutor:創(chuàng)建一個單線程的線程池,會用唯一的工作線程來執(zhí)行任務(wù)。保證所有任務(wù)按照指定順序去執(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() {@Overridepublic void run() {log.info("task:{}", index);}});}//一定要關(guān)閉線程池,否則程序不結(jié)束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() {@Overridepublic void run() {log.info("task:{}", index);}});}//一定要關(guān)閉線程池,否則程序不結(jié)束executorService.shutdown();} }

    輸出結(jié)果:

    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

    相當(dāng)于單線程按順序執(zhí)行。??

    Executors.newScheduledThreadPool代碼示例:

    @Slf4j public class ThreadPoolExample4 {public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);scheduledExecutorService.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {log.warn("schedule run");}},1, 3, TimeUnit.SECONDS);//這里不需要關(guān)閉線程池//scheduledExecutorService.shutdown();} }

    上面目的是:延遲1秒后,每個三秒執(zhí)行一次任務(wù),由于這個任務(wù)時不定的執(zhí)行,因此這里不應(yīng)該關(guān)閉線程池。如果需要關(guān)閉線程池的話,可以設(shè)置一個觸發(fā)條件來關(guān)閉。類似于Timer類:

    @Slf4j public class ThreadPoolExample4 {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {log.warn("timer run");}}, new Date(), 5*1000);} }

    線程池合理配置

    • CPU密集型任務(wù),就需要盡量壓榨CPU,參考值可以設(shè)置為NCPU+1
    • 如果是IO密集型任務(wù),參考值可以設(shè)置為2*NCPU

    ????我們只用線程池主要是為了重用存在的線程,減少對象創(chuàng)建消亡,能有效控制最大線程并發(fā)數(shù),可以避免過多的資源競爭和阻塞,也可以定時執(zhí)行單線程與控制線程的執(zhí)行性能比較好。?這不代表線程池應(yīng)該隨時隨地用,一定要根據(jù)自己的實際場景來分析使用參數(shù)配置

    總結(jié)

    以上是生活随笔為你收集整理的java高并发(十八)线程池的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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