java中四种线程池的区别
本文按:
一. 線程池的使用
二. 幾種線程池的區別
三. 如何合理配置線程池
一.線程池的使用
在Java中,通常使用Executors 獲取線程池。常用的線程池有以下幾種:
(1)CachedThreadPool
(2)FixedThreadPool
(3)ScheduledThreadPool(多核線程池)
(4)SingleThreadExecutor(單核線程池)
明確概念:阻塞隊列:
阻塞隊列(BlockingQueue)是一個支持兩個附加操作的隊列。這兩個附加的操作是:
(1)在隊列為空時,獲取元素的線程會等待隊列變為非空。
(2)當隊列滿時,存儲元素的線程會等待隊列可用。
二.幾種線程池的區別
(1)ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
核心線程數-0
最大線程數-Integer.MAX_VALUE
一個線程如果在 60還沒有被使用的話會被移除線程池
阻塞隊列使用SynchronousQueue
使用中斷的拒絕策略
特點:
1)按需創建新的線程,如果沒有可用線程則創建新的線程,之前用過的線程可能會再次被使用;
2)因為空閑線程會被移除線程池,因此,如果線程池長時間不被使用也不會消耗系統資源、
(2)ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);//nThread
核心線程數=最大線程數=參數nThread
阻塞隊列使用LinkedBlockingQueue,一個共享的無界隊列
特點:
1)在任何情況下最多只有nThread個線程工作,多余的Task將會被存放到隊列中等待;
2)如果線程在執行任務中被終止,終止之前會創建其他的線程代替原來的;
3)線程將會一直存在在線程池中,直到調用shutDown()方法
(3)ScheduledExecutorService scheduledThreadPool =Executors.newScheduledThreadPool(5);//corePoolSize
使用:
?void test(){scheduledThreadPool.schedule(new CallableTask(), 1, TimeUnit.DAYS);//CallableTask每天執行一次}核心線程數:通過參數指定corePoolSize
最大線程數:Integer.MAX_VALUE
超過corePoolSize的線程在執行完任務后即終止
阻塞隊列使用DelayedWorkQueue
特點:
1)核心線程數將會一直存在線程池中,除非設置了allowCoreThreadTimeOut
2)可以設置線程的執行時間
(4)ExecutorService singleExecutorService = Executors.newSingleThreadExecutor();
線程池中最多同時只有一個線程活躍
同一時刻只有一個任務執行
多余的任務放在LinkedBlockingQueue中
線程池的拒絕策略
先假設一個前提:線程池有一個任務隊列,用于緩存所有待處理的任務,正在處理的任務將從任務隊列中移除。因此在任務隊列長度有限的情況下就會出現新任務的拒絕處理問題,需要有一種策略來處理應該加入任務隊列卻因為隊列已滿無法加入的情況。另外在線程池關閉的時候也需要對任務加入隊列操作進行額外的協調處理。
RejectedExecutionHandler提供了四種方式來處理任務拒絕策略
1、直接丟棄(DiscardPolicy)
2、丟棄隊列中最老的任務(DiscardOldestPolicy)。
3、拋異常(AbortPolicy)
4、將任務分給調用線程來執行(CallerRunsPolicy)。
4、將任務分給調用線程來執行(CallerRunsPolicy)。
三. 如何合理配置線程池
要想合理的配置線程池,就必須首先分析任務特性,可以從以下幾個角度來進行分析:
任務的性質:CPU密集型任務,IO密集型任務和混合型任務。
任務的優先級:高,中和低。
任務的執行時間:長,中和短。
任務的依賴性:是否依賴其他系統資源,如數據庫連接。
任務性質不同的任務可以用不同規模的線程池分開處理。CPU密集型任務配置盡可能少的線程數量,如配置Ncpu+1個線程的線程池。IO密集型任務則由于需要等待IO操作,線程并不是一直在執行任務,則配置盡可能多的線程,如2*Ncpu。混合型的任務,如果可以拆分,則將其拆分成一個CPU密集型任務和一個IO密集型任務,只要這兩個任務執行的時間相差不是太大,那么分解后執行的吞吐率要高于串行執行的吞吐率,如果這兩個任務執行時間相差太大,則沒必要進行分解。我們可以通過Runtime.getRuntime().availableProcessors()方法獲得當前設備的CPU個數。
優先級不同的任務可以使用優先級隊列PriorityBlockingQueue來處理。它可以讓優先級高的任務先得到執行,需要注意的是如果一直有優先級高的任務提交到隊列里,那么優先級低的任務可能永遠不能執行。
執行時間不同的任務可以交給不同規模的線程池來處理,或者也可以使用優先級隊列,讓執行時間短的任務先執行。
依賴數據庫連接池的任務,因為線程提交SQL后需要等待數據庫返回結果,如果等待的時間越長CPU空閑時間就越長,那么線程數應該設置越大,這樣才能更好的利用CPU。
建議使用有界隊列,有界隊列能增加系統的穩定性和預警能力,可以根據需要設大一點,比如幾千。有一次我們組使用的后臺任務線程池的隊列和線程池全滿了,不斷的拋出拋棄任務的異常,通過排查發現是數據庫出現了問題,導致執行SQL變得非常緩慢,因為后臺任務線程池里的任務全是需要向數據庫查詢和插入數據的,所以導致線程池里的工作線程全部阻塞住,任務積壓在線程池里。如果當時我們設置成無界隊列,線程池的隊列就會越來越多,有可能會撐滿內存,導致整個系統不可用,而不只是后臺任務出現問題。當然我們的系統所有的任務是用的單獨的服務器部署的,而我們使用不同規模的線程池跑不同類型的任務,但是出現這樣問題時也會影響到其他任務。
?
Reference:
[1]https://blog.csdn.net/u010412719/article/details/52132613
?
總結
以上是生活随笔為你收集整理的java中四种线程池的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机之所以能实现自动连续运算是由于采用
- 下一篇: 搞笑聊天记录(聊天话题100个幽默句子)