Java多執行緒-----執行緒池詳解
阿新 • • 發佈:2019-01-05
1. 執行緒池的實現原理
提交一個任務到執行緒池中,執行緒池的處理流程如下:
- 判斷執行緒池裡的核心執行緒是否都在執行任務,如果不是(核心執行緒空閒或者還有核心執行緒沒有被建立)則建立一個新的工作執行緒來執行任務。如果核心執行緒都在執行任務,則進入下個流程
- 執行緒池判斷工作佇列是否已滿,如果工作佇列沒有滿,則將新提交的任務儲存在這個工作佇列裡。如果工作佇列滿了,則進入下個流程
- 判斷執行緒池裡的執行緒是否都處於工作狀態,如果沒有,則建立一個新的工作執行緒來執行任務。如果已經滿了,則交給飽和策略來處理這個任務
2. 執行緒池的優點
- 執行緒是稀缺資源,使用執行緒池可以減少建立和銷燬執行緒的次數,每個工作執行緒都可以重複使用
- 可以根據系統的承受能力,調整執行緒池中工作執行緒的數量,防止因為消耗過多記憶體導致伺服器崩潰
3. 執行緒的建立及使用
3.1 newCachedThreadPool()
建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒
這種型別的執行緒池特點是:
- 快取型池子,先檢視池中有沒有以前建立的執行緒,如果有,就reuse,如果沒有,就建立一個新的執行緒加入池中
- 快取型池子,通常用於執行一些生存週期很短的非同步型任務;因此一些面向連線的daemon型server中用得不多
- 能reuse的執行緒,必須是timeout IDLE內的池中執行緒,預設timeout是60s,超過這個IDLE時長,執行緒例項將被終止及移出池
- 注意,放入CachedThreadPool的執行緒不必擔心其結束,超過TIMEOUT不活動,其會自動被終止
package com.thread.threadpool;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒 * * @author yyx 2019年1月5日 */ public class CachedThreadPool { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 1; i <= 10; i++) { final int index = i; executorService.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "當前執行到:" + index); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } } }
3.2 newFixedThreadPool()
建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待
這種型別的執行緒池特點是:
- newFixedThreadPool與cacheThreadPool差不多,也是能reuse就用,但不能隨時建新的執行緒
- 其獨特之處:任意時間點,最多隻能有固定數目的活動執行緒存在,此時如果有新的執行緒要建立,只能放在另外的佇列中等待,直到當前的執行緒中某個執行緒終止直接被移出池子
- 和cacheThreadPool不同,FixedThreadPool沒有IDLE機制,所以FixedThreadPool多數針對一些很穩定很固定的正規併發執行緒,多用於伺服器
- 從方法的原始碼看,cache池和fixed 池呼叫的是同一個底層池,只不過引數不同:fixed池執行緒數固定,並且是0秒IDLE(無IDLE)cache池執行緒數支援0-Integer.MAX_VALUE(顯然完全沒考慮主機的資源承受能力),60秒IDLE
package com.thread.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待 * * @author yyx 2019年1月5日 */ public class FixedThreadPool { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); for (int i = 1; i <= 10; i++) { final int index = i; executorService.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "當前執行到:" + index); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } } }
3.3 newSingleThreadExecutor()
建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行
這種型別的執行緒池特點是:
- 單例執行緒,任意時間池中只能有一個執行緒
- 用的是和cache池和fixed池相同的底層池,但執行緒數目是1-1,0秒IDLE(無IDLE)
package com.thread.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行 * * @author yyx 2019年1月5日 */ public class SingleThreadExecutor { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 1; i <= 10; i++) { final int index = i; executorService.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "當前執行到:" + index); try { Thread.sleep(3000); } catch (Exception ex) { ex.printStackTrace(); } } }); } } }
3.4 newScheduledThreadPool()
建立一個定長執行緒池,支援定時及週期性任務執行
這種型別的執行緒池特點是:
- 排程型執行緒池
- 這個池子裡的執行緒可以按schedule依次delay執行,或週期執行
package com.thread.threadpool; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * 建立一個定長執行緒池,支援定時及週期性任務執行 * * @author yyx 2019年1月5日 */ public class ScheduledThreadPool { public static void main(String[] args) { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); scheduledExecutorService.schedule(new Runnable() { @Override public void run() { System.out.println("延遲3秒執行"); } }, 3, TimeUnit.SECONDS); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("延遲3秒後每1秒執行一次"); } }, 3, 1, TimeUnit.SECONDS); } }