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

一贩耐、線程和進程弧腥,線程的生命周期
二、單線程和多線程
三潮太、線程池的概念
四管搪、線程池的使用
五、多線程池配置示例

一铡买、線程和進程更鲁,線程的生命周期

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

二、單線程和多線程

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

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

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

三、線程池的概念

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

線程池使用目的
(1)避免反復創(chuàng)建和銷毀線程帶來的時間和內存消耗
(2)線程復用,提升響應速度,當有任務的時候乞巧,線程池直接調可用的線程進行執(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ù)量是辕,即便是線程池里沒有任何任務,也會有corePoolSize個線程在等任務
(2)maximumPoolSize:線程池中可以容納的最大線程的數(shù)量(3)keepAliveTime:非核心線程可以保留的最長的空閑時間猎提。當線程池里的線程數(shù)大于corePoolSize時获三,如果等了keepAliveTime時長還沒有任務可執(zhí)行,則線程退出锨苏。
(4)unit:用來指定keepAliveTime的單位疙教,比如秒:TimeUnit.SECONDS
(5)workQueue:等待隊列,任務可以儲存在任務隊列中等待被執(zhí)行伞租,采用FIFIO原則(先進先出)
(6)threadFactory:創(chuàng)建線程的線程工廠贞谓,主要是為了給線程起名字,默認工廠的線程名字:pool-1-thread-3葵诈。
(7)handler:線程池對拒絕任務(無線程可用)的處理策略裸弦,當線程池里線程被耗盡,且隊列也滿了的時候會調用

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

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

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

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

五槽奕、多線程池配置示例

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注解囱持,聲明該實體類對應的配置字段前綴
(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注解盔几,開啟異步任務
(3)在實例化方法上添加 @Bean 注解
getPrimaryAsyncTaskExecutor() 與 getSecondaryAsyncTaskExecutor() 方法分別實例化了對應的 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);
        // 線程池對拒絕任務(無線程可用)的處理策略
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return threadPoolTaskExecutor;
    }
}

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

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

/**
 * 文件描述
 * 任務異步處理
 * @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 調用異步任務

/**
 * 文件描述
 *
 * @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結果"+userInfoResult+"\nCompletableFuture耗時--》"+ (end-start)+"ms");
    }

從測試結果可以看到世曾,使用了第一個線程池


圖片.png

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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末缨恒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子轮听,更是在濱河造成了極大的恐慌肿轨,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蕊程,死亡現(xiàn)場離奇詭異椒袍,居然都是意外死亡,警方通過查閱死者的電腦和手機藻茂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門驹暑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辨赐,你說我怎么就攤上這事优俘。” “怎么了掀序?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵帆焕,是天一觀的道長。 經常有香客問我,道長叶雹,這世上最難降的妖魔是什么财饥? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮折晦,結果婚禮上钥星,老公的妹妹穿的比我還像新娘。我一直安慰自己满着,他們只是感情好谦炒,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著风喇,像睡著了一般宁改。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上魂莫,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天还蹲,我揣著相機與錄音,去河邊找鬼豁鲤。 笑死秽誊,一個胖子當著我的面吹牛,可吹牛的內容都是我干的琳骡。 我是一名探鬼主播锅论,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼楣号!你這毒婦竟也來了最易?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤炫狱,失蹤者是張志新(化名)和其女友劉穎藻懒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體视译,經...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡嬉荆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了酷含。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鄙早。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖椅亚,靈堂內的尸體忽然破棺而出限番,到底是詐尸還是另有隱情,我是刑警寧澤呀舔,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布弥虐,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏霜瘪。R本人自食惡果不足惜珠插,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粥庄。 院中可真熱鬧丧失,春花似錦豺妓、人聲如沸惜互。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽训堆。三九已至,卻和暖如春白嘁,著一層夾襖步出監(jiān)牢的瞬間坑鱼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工絮缅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鲁沥,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓耕魄,卻偏偏與公主長得像画恰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吸奴,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354