java多線程學習(線程池學習)(五)

線程池的作用

線程池的作用

線程的流程和原理

流程圖
文字

線程池的創建

線程學習的第二篇學習講過線程池的創建,使用的是google的guava

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>

Java提供的線程池

這裏是使用java先使用java自帶的幾種創建線程池的方式,直接看demo:

    private static void initThreadPool() {
        // 一個線程池,5個工作線程
        // ExecutorService threadPool = Executors.newFixedThreadPool(5);

        // 一個線程池,1個工作線程
        // ExecutorService threadPool = Executors.newSingleThreadExecutor();

        // 時間調度,可做定時
        // ExecutorService threadPool = Executors.newScheduledThreadPool(5);

        // ExecutorService threadPool = Executors.newWorkStealingPool();

        // 一個線程池, N個工作線程
        ExecutorService threadPool = Executors.newCachedThreadPool();

        try {
            for (int i = 1; i <= 10; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t辦理業務");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }

上面demo中有五種java提供的線程池,都能正常使用,但是不推薦這樣子做,阿里巴巴規範手冊裏面也不推薦這種做法,看看源碼就知道了:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

這裏的默認最大線程數Integer最大值,很容易造成錯誤操作導致的線程積壓,最後會導致OOM,詳細的規範和其他需要注意的地方可以參考阿里巴巴開發手冊。

根據這段代碼我們可以看出其底層使用的是:

new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                        60L, TimeUnit.SECONDS,
                        new SynchronousQueue<Runnable>());

其他幾種創建方式也是如此,可以點擊源碼參閱,這裏就不粘貼了。
根據這個我們便可知道,我們可以自己手動創建線程池;

自定義創建線程池

public static void main(String[] args) {
		// 查看自己電腦上的核心線程數
        System.out.println(Runtime.getRuntime().availableProcessors());
        ExecutorService threadPool = new ThreadPoolExecutor(2,
                5,
                2L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());
        try {
            for (int i = 1; i <= 10; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t辦理業務");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
        // initThreadPool();
    }

可以自行跑一下代碼,看結果,多測幾個臨界值(7、8、9);

這些參數的意思:
線程池的參數
主要講下第7個參數,handler,主要分爲四種:

線程滿了之後的策略:

  • AbortPolicy:直接拋出RejectedExecutionException異常,組織系統正常運行
  • CallerRunsPolicy: "調用者運行"一種調節機制,該策略既不會拋棄任務,也不會拋出異常,而是將某些任務回退到調用者,從而降低新任務的流量
  • DiscardOldestPolicy: 拋棄隊列中等待最久的任務,然後把當前任務加入隊列中嘗試在次提交當前任務
  • DiscardPolicy: 默默丟棄無法處理的任務,不予任何處理,也不拋出異常。如果允許任務丟失,這就是最好的策略

可以參考源碼:

public static class CallerRunsPolicy implements RejectedExecutionHandler{
...
}
public static class AbortPolicy implements RejectedExecutionHandler{
...
}
...

謝謝大家閱讀!!

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