1. 程式人生 > >線程池任務增長過程分析

線程池任務增長過程分析

system 意義 exec exe ise 核心線程 fin private throws

線程池配置參數如下:

    //線程緩沖隊列
    private static BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(10);
    // 核心線程數
    private static final int SIZE_CORE_POOL = 5;
    // 線程池維護線程的最大數量
    private static final int SIZE_MAX_POOL = 9;
    // 線程池維護線程所允許的空閑時間
    private static final long ALIVE_TIME = 2000;
    //創建線程池
    private static ThreadPoolExecutor pool = new ThreadPoolExecutor(SIZE_CORE_POOL, SIZE_MAX_POOL, ALIVE_TIME, TimeUnit.MILLISECONDS, bqueue, new ThreadPoolExecutor.CallerRunsPolicy());
    static {
        //這個方法一調用,會讓線程池立即初始化核心線程數相等數量的線程,如果不調用,初始線程數就是0,當有任務來的時候才會創建線程
        pool.prestartAllCoreThreads();
    }

ThreadPoolExecutor構造函數的參數意義不再多說,按照上面的參數配置,說明一下執行20個任務且每個任務執行時間1秒,線程池中的線程和隊列變化過程:
由於調用了prestartAllCoreThreads這個方法,線程池初始線程5個,添加前五個任務會分別占用一個線程執行,第六個任務開始會被放到bqueue隊列中,隊列長度是10所以到第15個任務的時候核心線程被占用,隊列也滿了,第16個任務就會創建新的線程執行,這些任務不經過隊列排隊所以會在隊列中任務之前執行,直到第19個任務線程數達到SIZE_MAX_POOL大小數量9,不再創建線程,第20個任務就會按照阻塞策略執行,CallerRunsPolicy這個策略的意思就是在調用者線程中直接執行任務,也是不經過排隊,效果和前面創建線程執行一樣,隨著任務被執行,隊列中的任務被消費掉隊列的長度也會恢復到0,空閑線程空閑時間超過2秒線程會關閉,最後保留5個線程存活,用一個main方法進行驗證:

    public static void main(String[] args) throws InterruptedException {
        for (int i = 1; i <= 20; i++) {
            System.out.println("線程池線程數:" + pool.getPoolSize() + ",隊列長度" + pool.getQueue().size());
            System.out.println("調用第" + i + "個任務");
            final int a = i;
            pool.execute(new Runnable() {

                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("完成第" + a + "個任務");
                }
            });
        }
        System.out.println("任務調用完成");
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            Thread.sleep(1000);
            System.out.println("線程池線程數:" + pool.getPoolSize() + ",隊列長度" + pool.getQueue().size());
        }
    }

執行結果:

線程池線程數:5,隊列長度0
調用第1個任務
線程池線程數:5,隊列長度1
調用第2個任務
線程池線程數:5,隊列長度1
調用第3個任務
線程池線程數:5,隊列長度1
調用第4個任務
線程池線程數:5,隊列長度0
調用第5個任務
線程池線程數:5,隊列長度1
調用第6個任務
線程池線程數:5,隊列長度1
調用第7個任務
線程池線程數:5,隊列長度2
調用第8個任務
線程池線程數:5,隊列長度3
調用第9個任務
線程池線程數:5,隊列長度4
調用第10個任務
線程池線程數:5,隊列長度5
調用第11個任務
線程池線程數:5,隊列長度6
調用第12個任務
線程池線程數:5,隊列長度7
調用第13個任務
線程池線程數:5,隊列長度8
調用第14個任務
線程池線程數:5,隊列長度9
調用第15個任務
線程池線程數:5,隊列長度10
調用第16個任務
線程池線程數:6,隊列長度10
調用第17個任務
線程池線程數:7,隊列長度10
調用第18個任務
線程池線程數:8,隊列長度10
調用第19個任務
線程池線程數:9,隊列長度10
調用第20個任務
完成第4個任務
完成第5個任務
完成第17個任務
完成第18個任務
完成第2個任務
完成第1個任務
完成第20個任務
完成第16個任務
完成第3個任務
任務調用完成
完成第19個任務
完成第6個任務
完成第12個任務
完成第9個任務
完成第14個任務
線程池線程數:9,隊列長度0
完成第8個任務
完成第10個任務
完成第11個任務
完成第7個任務
完成第13個任務
完成第15個任務
線程池線程數:9,隊列長度0
線程池線程數:9,隊列長度0
線程池線程數:5,隊列長度0
線程池線程數:5,隊列長度0
線程池線程數:5,隊列長度0
線程池線程數:5,隊列長度0

註釋掉靜態代碼塊中的pool.prestartAllCoreThreads();再執行線程數會從0開始,線程會在有任務執行的時候再去創建:

線程池線程數:0,隊列長度0
調用第1個任務
線程池線程數:1,隊列長度0
調用第2個任務
線程池線程數:2,隊列長度0
調用第3個任務
線程池線程數:3,隊列長度0
調用第4個任務
線程池線程數:4,隊列長度0
調用第5個任務
線程池線程數:5,隊列長度0
調用第6個任務
線程池線程數:5,隊列長度1
調用第7個任務
線程池線程數:5,隊列長度2
調用第8個任務
線程池線程數:5,隊列長度3
調用第9個任務
線程池線程數:5,隊列長度4
調用第10個任務
線程池線程數:5,隊列長度5
調用第11個任務
線程池線程數:5,隊列長度6
調用第12個任務
線程池線程數:5,隊列長度7
調用第13個任務
線程池線程數:5,隊列長度8
調用第14個任務
線程池線程數:5,隊列長度9
調用第15個任務
線程池線程數:5,隊列長度10
調用第16個任務
線程池線程數:6,隊列長度10
調用第17個任務
線程池線程數:7,隊列長度10
調用第18個任務
線程池線程數:8,隊列長度10
調用第19個任務
線程池線程數:9,隊列長度10
調用第20個任務
完成第1個任務
完成第2個任務
完成第3個任務
完成第4個任務
完成第5個任務
完成第18個任務
完成第19個任務
完成第20個任務
完成第17個任務
完成第16個任務
任務調用完成
完成第6個任務
完成第7個任務
完成第10個任務
完成第9個任務
完成第8個任務
線程池線程數:9,隊列長度0
完成第13個任務
完成第12個任務
完成第14個任務
完成第11個任務
完成第15個任務
線程池線程數:9,隊列長度0
線程池線程數:5,隊列長度0
線程池線程數:5,隊列長度0
線程池線程數:5,隊列長度0
線程池線程數:5,隊列長度0

線程池任務增長過程分析