Java多線程-ThreadPool線程池-1(三)

開完一趟車完整的過程是啓動、行駛和停車,但老司機都知道,真正費油的不是行駛,而是長時間的怠速、頻繁地踩剎車等動作。因爲在速度切換的過程中,發送機要多做一些工作,當然就要多費一些油。

而一個Java線程完整的生命週期就包括:

1、T1:創建(啓動)

2、T2:運行(行駛)

3、T3:銷燬(停車)

而T1 + T3的開銷(汽油或者時間)是要遠大於T2的。所以,即使是性能再好的車,或者性能再好的計算機,如果經常有T1 + T3的操作存在,那麼顯然是扛不住的。

所以,爲了解決這種因爲切換不同線程導致的效率問題,Java推出了線程池技術。通過對已創建線程的合理重用,既能解決上述問題,又能進一步提高響應速度,提升系統性能和穩定性。線程池特別適合下面的應用場景:

1、單個任務處理時間較短

2、需要處理的任務數量大

比如硬件數據採集,像手機、車載和安防傳感器的數據採集就特別符合這種情況。

這是線程池相關繼承結構圖:

很多人都分不清Executor和Executors這兩個東西:Executor是接口,是一個根據一組執行策略調用、調度、執行和控制的異步任務框架,提供了一種將“任務提交”與“任務如何運行”分離開的機制。而Executors則是一個工具類(不用new),提供了諸多用於線程池的靜態方法。Executor和Executors的關係,和Java I/O中Collection和Collections的關係一毛一樣。所以下次再看到XXX和XXXs的時候應該就知道Java的調性了。

說起來還是有點枯燥,那麼我拿之前做的一個例子來說一下就明白了。

假設有一個工地有若干項目經理和工人,1個經理+1個工人組成工作小隊,工地有很多個這樣的工作小隊,這些工作小隊需要加入項目組,但是隻有有活幹的才能加入,沒活幹的加不了,就能要被優化裁員。

/**
 * 工人
 */
public class Worker {
    /**
     * 幹活
     */
    public void dosomething() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("挖坑");
    }
}
/**
 * 經理
 */
public class Manager implements Runnable {
    private Worker worker;

    public Worker getWorker() {
        return worker;
    }

    public void setWorker(Worker worker) {
        this.worker = worker;
    }

    /**
     * 經理動嘴,工人動手
     */
    @Override
    public void run() {
        worker.dosomething();
    }
}
/**
 * 項目組
 */
public class ManagerGroup {
    private static ExecutorService projectGroup = new ThreadPoolExecutor(
            3, // 核心小隊數量
            3, // 最多能容納多少個小隊
            30, // 多久沒活幹就請出項目組
            TimeUnit.SECONDS, // 時間單位
            new ArrayBlockingQueue<Runnable>(3),// 有多少個項目經理就不再接收入組申請
            new ThreadPoolExecutor.CallerRunsPolicy() // 項目組拒絕響應時怎麼處理
    );

    // 項目組增加工作小隊
    public static void addTask(Manager manager) {
        projectGroup.execute(manager);
    }

    public static void main(String[] args) {
        Manager manager1 = new Manager();
        Worker worker1 = new Worker();
        manager1.setWorker(worker1);

        Manager manager2 = new Manager();
        Worker worker2 = new Worker();
        manager2.setWorker(worker2);

        Manager manager3 = new Manager();
        Worker worker3 = new Worker();
        manager3.setWorker(worker3);

        // 申請進入項目組有活幹纔可能不被優化
        ManagerGroup.addTask(manager1);
        ManagerGroup.addTask(manager2);
        ManagerGroup.addTask(manager3);
    }
}

可以自己將核心小組數量、最多能容納的小隊數量等數字調節一下,然後運行看看效果。

和線程一樣,線程池也有自己的狀態,而且和線程的狀態差不多(想想也是,畢竟要符合線程生命週期的東西,確實應該差不多)。線程池狀態:

 

 

1、RUNNING:正常運行,能接收新任務,也能處理阻塞隊列中的任務;

2、SHUTDOWN:關閉狀態,不接收新任務,但可以繼續處理阻塞隊列中已有任務;

3、STOP:既不接收新任務,也不處理隊列中的任務,並會中斷正在處理的任務;

4、TIDYING(這個名字叫得有點奇怪):如果所有任務都已中止,且workCount有效線程數爲0,則會調用terminated()方法進入TERMINATED狀態;

5、TERMINATED:terminated()方法執行完後進入該狀態,什麼也不做。

線程池運行時的流程圖:

 

 

 至於線程池的構造函數什麼的就不多囉嗦了,太枯燥無聊。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章