1. 程式人生 > >用ThreadPoolExecutor建立執行緒池的優點

用ThreadPoolExecutor建立執行緒池的優點

現在做開發的童鞋,越來越多的人在建立執行緒池用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建立的優點:

  1. 可以實時獲取執行緒池內執行緒的各種狀態
  2. 可以動態調整執行緒池大小
/**
 * 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;
    }
}