自定義線程池-線程池源碼筆記

池化技術

池化技術在java中有廣泛的運用,比如數據庫連接池,字符串池,以及線程池。之所以池化技術運用廣泛,在於他的優勢以線程池爲例):

  • 提高線程的利用率
  • 提高響應速度
  • 便於統一管理線程對象
  • 可控制最大併發數

線程池的設計思想

  • 核心池大小
  • 線程池最大容量
  • 等待隊列
  • 拒絕策略

在這裏插入圖片描述業務流程如下:

線程池啓動的時候會按照核⼼池的數來創建初始化的線程對象 2 個。
開始分配任務,如果同時來了多個任務, 2 個線程對象都被佔⽤了,第 3 個以及之後的任務進⼊等待隊列,當前有線程完成任務恢復空閒狀態的時候,等待隊列中的任務獲取線程對象。
如果等待隊列也佔滿了,⼜有新的任務進來,需要去協調,讓線程池再創建新的線程對象,但是線程池不可能⽆限去創建線程對象,⼀定會有⼀個最⼤上限,就是線程池的最⼤容量。
如果線程池已經達到了最⼤上限,並且等待隊列也佔滿了,此時如果有新的任務進來,只能選擇拒絕,並且需要根據拒絕策略來選擇對應的⽅案。

線程池代碼理解

1.Executors工具類的使用:

  1. ExecutorService e= Executors.newSingleThreadExecutor();(單線程)
    在這裏插入圖片描述
  2. ExecutorService executorService =Executors.newFixedThreadPool(5);(固定數量現線程池)
    在這裏插入圖片描述
  3. ExecutorService executorService = Executors.newCachedThreadPool();(緩存,線程數油電腦配置定)
    在這裏插入圖片描述

看上述三個Executors工具類源碼可發現他們有一個共同點:都是要new一個ThreadPoolExecutor 對象。ThreadPoolExecutor就是我們要重點理解的。

2.ThreadPoolExecutor

進入此類發現有許多不同參數的構造器,以便使用者靈活 創建自己需要的線程池。其中最重要的是理解7個參數:

corePoolSize:核⼼池的⼤⼩
maximumPoolSize:線程池的最⼤容量
keepAliveTime:線程存活時間(在沒有任務可執⾏的情況下),必須是線程池中的數量⼤於
corePoolSize,纔會⽣效
TimeUnit:存活時間單位
BlockingQueue:等待隊列,存儲等待執⾏的任務
ThreadFactory:線程⼯⼚,⽤來創建線程對象
RejectedExecutionHandler:拒絕策略

四種拒絕策略:

1、AbortPolicy:直接拋出異常
2、DiscardPolicy:放棄任務,不拋出異常
3、DiscardOldestPolicy:嘗試與等待隊列中最前⾯的任務去爭奪,不拋出異常
4、CallerRunsPolicy:誰調⽤誰處理

代碼實驗

已知以上概念,我們可以很輕易地寫出自己想要的線程池。
主要代碼:

package com.blog.www.common;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.*;

/**
 * @version 1.0
 * @date 2020/3/8 21:37
 */
public class test {
    public static void main(String[] args) {
        //定製化線程池
        ExecutorService executorService = new ThreadPoolExecutor(2,3,0L,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(2),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        for(int i=0;i<1;i++){
            executorService.execute(()->{
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"===>辦理業務");
            });
        }
    }
}

1.i<1時,單線程結果很明顯:
在這裏插入圖片描述2、i<2時候,此時正好達到核心線程數(結果不唯一)
在這裏插入圖片描述3、i<3時,for是併發的,第三個任務來會進入等待隊列,不會新開線程。
在這裏插入圖片描述4、i<4時,和上面相同,只不過等待隊列剛好滿了
5、i<5時,第五個任務來了,此時兩個核心線程在運行,等待隊列也滿了,所以線程池會再創建一個線程,此時就達到我們設置的最大線程上限了。
在這裏插入圖片描述
6.i<6時,第六個任務來了,此時等待隊列滿了,也已達到最大線程上限。故只有拒絕此任務。
在這裏插入圖片描述7.i<7時,第七個任務來了。因爲拒絕了第六個任務,同時也有其他任務結束的,故第七個任務也有可能正常執行,當然也有可能被拒絕。這裏要改一下主代碼,因爲決絕策略用的是AbortPolicy直接拋出異常,這樣看不出來效果。換成CallerRunsPolicy:誰調⽤誰處理。
在這裏插入圖片描述8.i<8時,多一點就可以看出來,後面的任務還有可能被執行的。
在這裏插入圖片描述
至此,定製線程池成功!

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