Springboot | 線程池的學習,多線程池配置示例

一、線程和進程,線程的生命周期
二、單線程和多線程
三、線程池的概念
四、線程池的使用
五、多線程池配置示例

一、線程和進程,線程的生命周期

鏈接:http://www.lxweimin.com/p/5ddcc068d177

二、單線程和多線程

單線程:只有一條線程在執(zhí)行任務(wù)

多線程:多條線程同時在執(zhí)行任務(wù),比較常見的一種方式。

多線程的安全問題:
在多線程執(zhí)行過程中,需要注意的是多線程的安全問題。因為多條線程同時執(zhí)行任務(wù),可能會出現(xiàn)同時訪問同一個資源的情況,導致出錯。所以需要進行同步互斥訪問處理: 使用synchronized 同步代碼塊和 Lock 鎖,只讓一個線程訪問資源,避免其他線程同時搶到CPU資源的執(zhí)行權(quán)。

三、線程池的概念

線程池概念:簡單的說,線程池是一個存放線程的容器。有任務(wù)時,從線程池里頭取線程,不用的時候再放到池中給別的任務(wù)使用。

線程池使用目的
(1)避免反復(fù)創(chuàng)建和銷毀線程帶來的時間和內(nèi)存消耗
(2)線程復(fù)用,提升響應(yīng)速度,當有任務(wù)的時候,線程池直接調(diào)可用的線程進行執(zhí)行,不需要等待線程的創(chuàng)建
(3)對線程進行統(tǒng)一的分配,提高線程的管理性

四、線程池的使用

4.1 線程池的創(chuàng)建

java中創(chuàng)建線程池的一個類:Executor,通常使用它的一個子類:ThreadPoolExecutor。

public ThreadPoolExecutor(
      int corePoolSize,  
      int maximumPoolSize,  
      long keepAliveTime,  
      TimeUnit unit,  
      BlockingQueue workQueue,  
      ThreadFactory threadFactory,  
      RejectedExecutionHandler handler)

線程池這幾個參數(shù)的解釋
(1)corePoolSize:線程池中的核心線程數(shù)量,即便是線程池里沒有任何任務(wù),也會有corePoolSize個線程在等任務(wù)
(2)maximumPoolSize:線程池中可以容納的最大線程的數(shù)量(3)keepAliveTime:非核心線程可以保留的最長的空閑時間。當線程池里的線程數(shù)大于corePoolSize時,如果等了keepAliveTime時長還沒有任務(wù)可執(zhí)行,則線程退出。
(4)unit:用來指定keepAliveTime的單位,比如秒:TimeUnit.SECONDS
(5)workQueue:等待隊列,任務(wù)可以儲存在任務(wù)隊列中等待被執(zhí)行,采用FIFIO原則(先進先出)
(6)threadFactory:創(chuàng)建線程的線程工廠,主要是為了給線程起名字,默認工廠的線程名字:pool-1-thread-3。
(7)handler:線程池對拒絕任務(wù)(無線程可用)的處理策略,當線程池里線程被耗盡,且隊列也滿了的時候會調(diào)用

線程池的拒絕策略包括以下4種:
ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出異常
ThreadPoolExecutor.DiscardPolicy:丟棄任務(wù),但是不拋出異常
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù),然后重新提交被拒絕的任務(wù)
ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程(提交任務(wù)的線程)處理該任務(wù)

4.2 線程池的執(zhí)行流程

線程池的執(zhí)行流程圖.jpg

step1:任務(wù)到達時,先判斷當前線程數(shù)量是否小于核心線程數(shù)corePoolSize,若小于則創(chuàng)建線程來執(zhí)行任務(wù),否則將任務(wù)放入workQueue等待隊列
step2:若workQueue等待隊列滿了,則判斷當前線程數(shù)量是否小于最大線程數(shù)maximumPoolSize,若小于則創(chuàng)建線程執(zhí)行任務(wù),否則就會調(diào)用handler,線程池采用拒絕策略來處理任務(wù)。

五、多線程池配置示例

5.1 添加依賴

該依賴的作用是用于配置類和實體類的字段定位

        <!--用于配置類和實體類的字段定位-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

5.2 定義基類,定義線程池基本參數(shù)

/**
 * 文件描述
 * 線程池基本參數(shù)
 * @author hjj
 * @date 2020年08月19日 15:43
 */
@Data
public class AsyncContants {
    /**
     * 核心線程數(shù)
     */
    private Integer corePoolSize=10;

    /**
     * 最大線程數(shù)
     */
    private Integer maxPoolSize=20;

    /**
     * 等待隊列
     */
    private Integer queueCapacity=50;

    /**
     *線程池維護線程所允許的空閑時間,單位為秒
     */
    private Integer keepAliveSeconds=120;

}

5.3 配置文件中配置線程池基本參數(shù)值

#線程池配置
#第一個線程池
primary.async.corePoolSize=10
primary.async.maxPoolSize=20
primary.async.queueCapacity=50
primary.async.keepAliveSeconds=120
#第二個線程池
secondary.async.corePoolSize=20
secondary.async.maxPoolSize=40
secondary.async.queueCapacity=100
secondary.async.keepAliveSeconds=120

5.4 定義多個線程池配置類

讀取配置文件,進行線程池配置
(1)添加@Component注解,聲明該類為 Spring 組件,交由容器管理
(2)添加@ConfigurationProperties注解,聲明該實體類對應(yīng)的配置字段前綴
(3)繼承AsyncContants基類

/**
 * 文件描述
 * 讀取配置文件,進行線程池配置
 * @author hjj
 * @date 2020年08月19日 15:49
 */
@Component
@ConfigurationProperties(value = "primary.async")
public class PrimaryAsyncContants extends AsyncContants{
}
/**
 * 文件描述
 * 讀取配置文件,進行線程池配置
 * @author hjj
 * @date 2020年08月19日 15:50
 */
@Component
@ConfigurationProperties(value = "secondary.async")
public class SecondaryAsyncConstants extends AsyncContants{
}

5.5線程池的自定義配置

將配置信息注入到線程池對象 ThreadPoolTaskExecutor 中,生成可用的 Executor 對象
(1)添加@Configuration注解
(2)添加@EnableAsync注解,開啟異步任務(wù)
(3)在實例化方法上添加 @Bean 注解
getPrimaryAsyncTaskExecutor() 與 getSecondaryAsyncTaskExecutor() 方法分別實例化了對應(yīng)的 Executor 對象,并通過注解 @Bean 將其納入容器中
后續(xù)需要使用線程池,直接引用Bean名稱

/**
 * 文件描述
 * 多個線程池自定義配置
 * @author hjj
 * @date 2020年08月19日 15:56
 */
@Configuration
@EnableAsync
public class AsyncTaskPoolConfig {

    private PrimaryAsyncContants primaryAsyncContants;
    private SecondaryAsyncConstants secondaryAsyncConstants;

    @Autowired(required = false)
    public AsyncTaskPoolConfig(PrimaryAsyncContants primaryAsyncContants, SecondaryAsyncConstants secondaryAsyncConstants){
        this.primaryAsyncContants = primaryAsyncContants;
        this.secondaryAsyncConstants = secondaryAsyncConstants;
    }

    @Bean(name = "primaryAsyncTaskExecutor")
    public Executor getPrimaryAsyncTaskExecutor(){
        return initExecutor(primaryAsyncContants,"primaryAsyncTaskExecutor-");
    }

    @Bean(name = "secondaryAsyncTaskExecutor")
    public Executor getSecondaryAsyncTaskExecutor(){
        return initExecutor(secondaryAsyncConstants,"secondaryAsyncTaskExecutor-");
    }

    private ThreadPoolTaskExecutor initExecutor(AsyncContants asyncContants,String prefix){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(asyncContants.getCorePoolSize());
        threadPoolTaskExecutor.setMaxPoolSize(asyncContants.getMaxPoolSize());
        threadPoolTaskExecutor.setQueueCapacity(asyncContants.getQueueCapacity());
        threadPoolTaskExecutor.setKeepAliveSeconds(asyncContants.getKeepAliveSeconds());
        threadPoolTaskExecutor.setThreadNamePrefix(prefix);
        // 線程池對拒絕任務(wù)(無線程可用)的處理策略
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return threadPoolTaskExecutor;
    }
}

5.6 編寫異步任務(wù)的實現(xiàn)方法

(1)添加@Async注解,引用剛才定義的線程池Bean名稱
(2)添加@Component注解,保證可以組件被掃描到
注:異步任務(wù)的實現(xiàn)方法要定義在一個類中,不能與調(diào)用它的方法寫在同一個類中,不然不起效果

/**
 * 文件描述
 * 任務(wù)異步處理
 * @author hjj
 * @date 2020年07月22日 16:33
 */
@Component
@Slf4j
public class AsyncTask {

    @Async("primaryAsyncTaskExecutor")
    public CompletableFuture<String> getUserInfoByCompletableFuture(String userName) {
            String userInfo="";
            try{
                Thread.sleep(10);
                userInfo = userName+"的基本信息!";
                log.info("線程:"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                log.error(e.getMessage(),e);
                e.printStackTrace();
            }
        return CompletableFuture.completedFuture(userInfo);
    }
}

5.7 調(diào)用異步任務(wù)

/**
 * 文件描述
 *
 * @author hjj
 * @date 2020年07月22日 16:48
 */
@Component
@Slf4j
public class CompletableFutureDemo {
    @Autowired
    private AsyncTask asyncTask;

    List<String> batchGetUserInfoByCompletableFuture(List<String> userNameList) throws InterruptedException, ExecutionException{
        List<CompletableFuture<String>>  userInfoFutrues = userNameList.stream().map(userName->asyncTask.getUserInfoByCompletableFuture(userName)).collect(Collectors.toList());
        return userInfoFutrues.stream().map(CompletableFuture::join).collect(Collectors.toList());
    }
}

5.8 測試

 @Test
    public void CompletableFutureTest()throws InterruptedException, ExecutionException {
        List<String> userNameList = new ArrayList<>();
        for(int i=0;i<5;i++){
            userNameList.add("Ada"+i);
        }
        long start =System.currentTimeMillis();
        List<String> userInfoResult = completableFutureDemo.batchGetUserInfoByCompletableFuture(userNameList);
        long end =System.currentTimeMillis();
        log.info("CompletableFuture結(jié)果"+userInfoResult+"\nCompletableFuture耗時--》"+ (end-start)+"ms");
    }

從測試結(jié)果可以看到,使用了第一個線程池


圖片.png

參考:
https://www.cnblogs.com/monkay/p/11170421.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380