摘要:在開發過程中,合理地使用線程池能夠帶來個好處。性質不同的任務可以交給不同規模的線程池執行。當然具體合理線程池值大小,需要結合系統實際情況,在大量的嘗試下比較才能得出,以上只是前人總結的規律。
線程池簡述
Java中的線程池是運用場景最多的并發框架,幾乎所有需要異步或并發執行任務的程序都可以使用線程池。在開發過程中,合理地使用線程池能夠帶來3個好處。
降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的消耗
提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行
提高線程的可管理性。線程是稀缺資源,如果無限制地創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一分配、調優和監控
線程池是為突然大量爆發的線程設計的,通過有限的幾個固定線程為大量的操作服務,減少了創建和銷毀線程所需的時間,從而提高效率。
如果一個線程的時間非常長,就沒必要用線程池了(不是不能作長時間操作,而是不宜。),況且我們還不能控制線程池中線程的開始、掛起、和中止
Executor框架的最頂層實現是ThreadPoolExecutor類,Executors工廠類中提供的newScheduledThreadPool、newFixedThreadPool、newCachedThreadPool方法其實也只是ThreadPoolExecutor的構造函數參數不同而已。通過傳入不同的參數,就可以構造出適用于不同應用場景下的線程池
corePoolSize: 核心池的大小。 當有任務來之后,就會創建一個線程去執行任務,當線程池中的線程數目達到corePoolSize后,就會把到達的任務放到緩存隊列當中
maximumPoolSize: 線程池最大線程數,它表示在線程池中最多能創建多少個線程;
keepAliveTime: 表示線程沒有任務執行時最多保持多久時間會終止。
unit: 參數keepAliveTime的時間單位,有7種取值
創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
線程池為無限大,當執行第二個任務時第一個任務已經完成,會復用執行第一個任務的線程,而不用每次新建線程
創建一個定長線程池,可控制線程最大并發數,超出的線程會在隊列中等待
定長線程池的大小最好根據系統資源進行設置。如Runtime.getRuntime().availableProcessors()
創建一個定長線程池,支持定時及周期性任務執行
newSingleThreadExecutor創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行
線程池原理提交一個任務到線程池中,線程池的處理流程如下:
1、判斷線程池里的核心線程是否都在執行任務,如果不是(核心線程空閑或者還有核心線程沒有被創建)則創建一個新的工作線程來執行任務。如果核心線程都在執行任務,則進入下個流程。
2、線程池判斷工作隊列是否已滿,如果工作隊列沒有滿,則將新提交的任務存儲在這個工作隊列里。如果工作隊列滿了,則進入下個流程。
3、判斷線程池里的線程是否都處于工作狀態,如果沒有,則創建一個新的工作線程來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。
CPU密集
CPU密集的意思是該任務需要大量的運算,而沒有阻塞,CPU一直全速運行。
CPU密集任務只有在真正的多核CPU上才可能得到加速(通過多線程),而在單核CPU上,無論你開幾個模擬的多線程,該任務都不可能得到加速,因為CPU總的運算能力就那些。
IO密集
IO密集型,即該任務需要大量的IO,即大量的阻塞。在單線程上運行IO密集型的任務會導致浪費大量的CPU運算能力浪費在等待。所以在IO密集型任務中使用多線程可以大大的加速程序運行,即時在單核CPU上,這種加速主要就是利用了被浪費掉的阻塞時間
要想合理的配置線程池的大小,首先得分析任務的特性,可以從以下幾個角度分析:
任務的性質:CPU密集型任務、IO密集型任務、混合型任務。
任務的優先級:高、中、低。
任務的執行時間:長、中、短。
任務的依賴性:是否依賴其他系統資源,如數據庫連接等。
性質不同的任務可以交給不同規模的線程池執行。
對于不同性質的任務來說,CPU密集型任務應配置盡可能小的線程,如配置CPU個數+1的線程數,IO密集型任務應配置盡可能多的線程,因為IO操作不占用CPU,不要讓CPU閑下來,應加大線程數量,如配置兩倍CPU個數+1,而對于混合型的任務,如果可以拆分,拆分成IO密集型和CPU密集型分別處理,前提是兩者運行的時間是差不多的,如果處理時間相差很大,則沒必要拆分了。
若任務對其他系統資源有依賴,如某個任務依賴數據庫的連接返回的結果,這時候等待的時間越長,則CPU空閑的時間越長,那么線程數量應設置得越大,才能更好的利用CPU。
當然具體合理線程池值大小,需要結合系統實際情況,在大量的嘗試下比較才能得出,以上只是前人總結的規律。
最佳線程數目 = ((線程等待時間+線程CPU時間)/線程CPU時間 )* CPU數目
比如平均每個線程CPU運行時間為0.5s,而線程等待時間(非CPU運行時間,比如IO)為1.5s,CPU核心數為8,那么根據上面這個公式估算得到:((0.5+1.5)/0.5)*8=32。這個公式進一步轉化為:
最佳線程數目 = (線程等待時間與線程CPU時間之比 + 1)* CPU數目
可以得出一個結論:
線程等待時間所占比例越高,需要越多線程。線程CPU時間所占比例越高,需要越少線程。
以上公式與之前的CPU和IO密集型任務設置線程數基本吻合。
CPU密集型時,任務可以少配置線程數,大概和機器的cpu核數相當,這樣可以使得每個線程都在執行任務
IO密集型時,大部分線程都阻塞,故需要多配置線程數,2*cpu核數
操作系統之名稱解釋:
某些進程花費了絕大多數時間在計算上,而其他則在等待I/O上花費了大多是時間,
前者稱為計算密集型(CPU密集型)computer-bound,后者稱為I/O密集型,I/O-bound。
代碼
@RequestMapping("test-threadpool") public void testThreadPool() { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 6, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3)); for (int i = 0; i < 6; i++) { TaskThred t1 = new TaskThred("任務" + i); threadPoolExecutor.execute(t1); } threadPoolExecutor.shutdown(); }
class TaskThred implements Runnable { private String taskName; public TaskThred(String taskName) { this.taskName = taskName; } @Override public void run() { System.out.println(Thread.currentThread().getName()+taskName); } }
結果
pool-1-thread-2任務4
pool-1-thread-1任務0
pool-1-thread-1任務1
pool-1-thread-1任務2
pool-1-thread-1任務3
pool-1-thread-3任務5
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74741.html
摘要:本文只介紹中線程池的基本使用,不會過多的涉及到線程池的原理。可緩存線程的線程池創建一個可緩存線程的線程池。首先是從接口繼承到的方法使用該方法即將一個任務交給線程池去執行。方法方法的作用是向線程池發送關閉的指令。 首先,我們為什么需要線程池?讓我們先來了解下什么是 對象池 技術。某些對象(比如線程,數據庫連接等),它們創建的代價是非常大的 —— 相比于一般對象,它們創建消耗的時間和內存都...
摘要:最后,我們會通過對源代碼的剖析深入了解線程池的運行過程和具體設計,真正達到知其然而知其所以然的水平。創建線程池既然線程池是一個類,那么最直接的使用方法一定是一個類的對象,例如。單線程線程池單線程線程 我們一般不會選擇直接使用線程類Thread進行多線程編程,而是使用更方便的線程池來進行任務的調度和管理。線程池就像共享單車,我們只要在我們有需要的時候去獲取就可以了。甚至可以說線程池更棒,...
摘要:每個通過網絡到達服務器的連接都被包裝成一個任務并且傳遞給線程池。線程池的線程會并發的處理連接上的請求。用線程池控制線程數量,其他線程排隊等候。實現包,線程池頂級接口是但是嚴格意義講并不是一個線程。此線程池支持定時以及周期性執行任務的需求。 tutorial site1tutorial site2 一個問題: 每啟動一個新線程都會有相應的性能開銷(涉及到OS的交互:創建線程,銷毀線程...
閱讀 3316·2021-11-16 11:45
閱讀 4387·2021-09-22 15:38
閱讀 2841·2021-09-22 15:26
閱讀 3347·2021-09-01 10:48
閱讀 827·2019-08-30 15:56
閱讀 715·2019-08-29 13:58
閱讀 1487·2019-08-28 18:00
閱讀 2160·2019-08-27 10:53