用ThreadPoolExecutor建立執行緒池的優點
阿新 • • 發佈:2018-12-27
現在做開發的童鞋,越來越多的人在建立執行緒池用ThreadPoolExecutor,而不是用JDK提供的四種方法來建立
一、執行緒池的背景:
1、執行緒是稀缺資源,使用執行緒池可以減少建立和銷燬執行緒的次數,每個工作執行緒都可以重複使用。
2、可以根據系統的承受能力,調整執行緒池中工作執行緒的數量,防止因為消耗過多記憶體導致伺服器崩潰。
二、核心引數:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
corePoolSize:執行緒池核心執行緒數量
maximumPoolSize:執行緒池最大執行緒數量
keepAliverTime:當活躍執行緒數大於核心執行緒數時,空閒的多餘執行緒最大存活時間
unit:存活時間的單位
workQueue:存放任務的佇列
handler:超出執行緒範圍和佇列容量的任務的處理程式
三、實現原理:
提交一個任務到執行緒池中,執行緒池的處理流程如下:
1、判斷執行緒池裡的核心執行緒是否都在執行任務,如果不是(核心執行緒空閒或者還有核心執行緒沒有被建立)則建立一個新的工作執行緒來執行任務。如果核心執行緒都在執行任務,則進入下個流程。
2、執行緒池判斷工作佇列是否已滿,如果工作佇列沒有滿,則將新提交的任務儲存在這個工作佇列裡。如果工作佇列滿了,則進入下個流程。
3、判斷執行緒池裡的執行緒是否都處於工作狀態,如果沒有,則建立一個新的工作執行緒來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。
採用ThreadPoolExecutor建立的優點:
- 可以實時獲取執行緒池內執行緒的各種狀態
- 可以動態調整執行緒池大小
/** * ThreadPoolExecutor類的使用方法 * 實現高併發:線上程類中的run()方法內設定Thread.sleep(long delta); delta取值為:(併發開始時間戳 - 執行緒開始時間戳) * Created by Administrator on 2016/11/19. */ public class ThreadPoolExecutorTest { public static void main(String[] args) { //設定核心池大小 int corePoolSize = 5; //設定執行緒池最大能接受多少執行緒 //當前執行緒數大於corePoolSize、小於maximumPoolSize時,超出corePoolSize的執行緒數的生命週期 long keepActiveTime = 200; //設定時間單位,秒 TimeUnit timeUnit = TimeUnit.SECONDS; //設定執行緒池快取佇列的排隊策略為FIFO,並且指定快取佇列大小為5 BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(5); //建立ThreadPoolExecutor執行緒池物件,並初始化該物件的各種引數 ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepActiveTime, timeUnit,workQueue); //往執行緒池中迴圈提交執行緒 for (int i = 0; i < 15; i++) { //建立執行緒類物件 MyTask myTask = new MyTask(i); //開啟執行緒 executor.execute(myTask); //獲取執行緒池中執行緒的相應引數 System.out.println("執行緒池中執行緒數目:" +executor.getPoolSize() + ",佇列中等待執行的任務數目:"+executor.getQueue().size() + ",已執行完的任務數目:"+executor.getCompletedTaskCount()); } //待執行緒池以及快取佇列中所有的執行緒任務完成後關閉執行緒池。 executor.shutdown(); } } /** *執行緒類 */ class MyTask implements Runnable { private int num; public MyTask(int num) { this.num = num; } @Override public void run() { System.out.println("正在執行task " + num ); try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task " + num + "執行完畢"); } /** * 獲取(未來時間戳-當前時間戳)的差值, * 也即是:(每個執行緒的睡醒時間戳-每個執行緒的入睡時間戳) * 作用:用於實現多執行緒高併發 * @return * @throws ParseException */ public long getDelta() throws ParseException { //獲取當前時間戳 long t1 = new Date().getTime(); //獲取未來某個時間戳(自定義,可寫入配置檔案) String str = "2016-11-11 15:15:15"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); long t2 = simpleDateFormat.parse(str).getTime(); return t2 - t1; } }