異步&線程池&異步編排

異步&線程池&異步編排

初始化線程的4種方式

  1. 繼承Thread
  2. 實現(xiàn)Runnable接口
  3. 實現(xiàn)Callable接口+FutureTask(可以拿到返回結(jié)果,可以處理異常)
  4. 線程池(推薦使用)

創(chuàng)建線程池

  1. 使用Executors創(chuàng)建
// 當前系統(tǒng)中池只有一兩個,每個異步任務溢陪,提交給線程池去執(zhí)行
public static ExecutorService service = Executors.newFixedThreadPool(10);
  1. new原生的ThreadPoolExecutor
/**
* int corePoolSize:核心線程數(shù) 線程池創(chuàng)建好之后就準備就緒的線程數(shù)量來接受異步任務執(zhí)行
* int maximumPoolSize:最大線程數(shù)量棍厌,控制資源
* long keepAliveTime:存活時間泵琳,釋放空閑線程(maximumPoolSize-corePoolSize)的存活時間
* TimeUnit unit:時間單位
* BlockingQueue<Runnable> workQueue:阻塞隊列,異步任務過多將多的任務放在隊只要有線程空閑 就去隊列里面取出新的任務繼續(xù)執(zhí)行
*  1. new LinkedBlockingQueue<>():默認是Integer的最大值蜈七,根據(jù)服務器并發(fā)量決定,要傳入指定的數(shù)量
* ThreadFactory threadFactory:線程的創(chuàng)建工廠
* RejectedExecutionHandler handler:如果阻塞隊列滿了按照指定的拒絕策略拒絕執(zhí)行任務
*  1. DiscardOldestPolicy 丟棄最老的任務
*  2. CallerRunsPolicy 直接調(diào)用線程自己的run方法乱凿,同步調(diào)用
*  3. AbortPolicy 丟棄新來的任務拋出異常
*  4. DiscardPolicy 丟棄新來的任務不拋異常
*/
new ThreadPoolExecutor(5, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

運行流程

  1. 線程池創(chuàng)建,準備好core數(shù)量的核心線程础倍,準備接受任務
  2. 新的任務進來烛占,用core準備好的空閑線程執(zhí)行
    1. core滿了,就將再進來的任務放入阻塞隊列沟启,空閑的core就會自己去阻塞隊列獲取任務執(zhí)行
    2. 阻塞隊列滿了忆家,就直接開新線程執(zhí)行,最大只能開到max指定的數(shù)量
    3. max都執(zhí)行好了德迹,max-core數(shù)量的空閑線程會在keepAliveTime指定的時間之后自動銷毀芽卿,最終保持到core大小
    4. 如果線程數(shù)開到了max數(shù)量,還有新的任務進來浦辨,就會使用reject指定的拒絕策略進行處理
  3. 所有的線程創(chuàng)建都是由指定的factory創(chuàng)建

常見線程池

  • newCachedThreadPool:創(chuàng)建一個可緩存線程池,如果線程池長度超過處理需要沼沈,可靈活回收空閑線程流酬,若無可回收,則新建線程
  • newFixedThreadPool:創(chuàng)建一個定長線程池列另,可控制線程池最大并發(fā)數(shù)芽腾,超出的線程會在隊列中等待
  • newScheduledThreadPool:創(chuàng)建一個定長線程池,支持定時及周期性任務執(zhí)行
  • newSingleThreadExecutor:創(chuàng)建一個單線程化的線程池页衙,它只會用唯一的工作線程來執(zhí)行任務摊滔,保證所有任務有序執(zhí)行

CompletableFuture異步編排

創(chuàng)建異步對象

  1. runAsync無返回值
/**
 * 異步執(zhí)行沒有返回值
 * Runnable runnable:要異步執(zhí)行的線程
 * Executor executor:執(zhí)行該線程的線程池
 */
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
    System.out.println("thread: " + Thread.currentThread().getId());
    int i = 10 / 2;
}, executor);
  1. supplyAsync有返回值
/**
 * 異步執(zhí)行有返回值
 * Supplier<U> supplier:要異步執(zhí)行的線程
 * Executor executor:執(zhí)行該線程的線程池
 */
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
    System.out.println("thread: " + Thread.currentThread().getId());
    int i = 10 / 2;
    return i;
}, executor);
Integer i = completableFuture.get();
System.out.println(i);

完成回調(diào)和異步感知

  1. whenComplete可以處理正常和異常的計算結(jié)果阴绢,exceptionally處理異常情況

whenComplete和whenCompleteAsync的區(qū)別

1. whenComplete:是執(zhí)行當前任務的線程繼續(xù)執(zhí)行whenComplete任務
2. whenCompleteAsync:是把whenCompleteAsync這個任務提交給線程池來執(zhí)行

方法不以Async結(jié)尾,意味著Action使用相同的線程執(zhí)行艰躺,而Async可能會使用其他線程執(zhí)行

        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("thread: " + Thread.currentThread().getId());
            int i = 10 / 0;
            return i;
        }, executor).whenComplete((res, exception) -> {
            // 能夠感知異常信息呻袭,但是沒法修改返回數(shù)據(jù)
            System.out.println("異步任務完成,結(jié)果是: " + res);
            System.out.println("異常是: " + exception);
        }).exceptionally(throwable -> {
            // 能夠感知異常信息腺兴,同時返回默認值
            return 10;
        });

handle最終處理

方法執(zhí)行完成后的處理 可以接受返回參數(shù)左电,感知異常,有返回值
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
    System.out.println("thread: " + Thread.currentThread().getId());
    int i = 10 / 0;
    return i;
}, executor).handle((res, exception) -> {
    if (res != null) {
        return res;
    }
    if (exception != null) {
        return 0;
    }
    return 1;
});

線程串行化

帶有Async默認是異步執(zhí)行页响,串行化需要前置任務成功完成

  1. thenApply方法:當一個線程依賴另一個線程時篓足,獲取上一個任務返回的結(jié)果,并返回當前任務的返回值
  2. thenAccept方法:消費處理結(jié)果闰蚕。接收任務的處理結(jié)果栈拖,并消費處理,無返回結(jié)果
  3. thenRun方法:只要上面的任務執(zhí)行完成没陡,就開始執(zhí)行thenRun涩哟,只是處理完任務后,執(zhí)行后續(xù)操作
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
    System.out.println("執(zhí)行任務一");
    return 1;
}, executor).thenApply((res) -> {
    System.out.println("執(zhí)行任務二");
    return 2;
});

組合任務--多任務組合

  1. allOf:等待所有任務完成
  2. anyOf:只要一個任務完成
// all Of
CompletableFuture<Void> allOf = CompletableFuture.allOf(completableFuture1, completableFuture2, completableFuture3);
// 等待所有結(jié)果執(zhí)行完成 阻塞式等待
allOf.get();
// 全部執(zhí)行完畢诗鸭,獲取執(zhí)行結(jié)果
System.out.println(completableFuture1.get() + ";" + completableFuture2.get() + ";" + completableFuture3.get());
// any Of
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(completableFuture1, completableFuture2, completableFuture3);
// 等待其中一個結(jié)果執(zhí)行完成 阻塞式等待
anyOf.get();
// 其中一個執(zhí)行完畢染簇,獲取執(zhí)行結(jié)果
System.out.println(anyOf.get());

組合任務--兩個任務必須都完成,觸發(fā)該任務

  1. thenCombine:組合兩個future强岸,獲取兩個future的返回結(jié)果锻弓,并返回當前任務的返回值
  2. thenAcceptBoth:組合兩個future规揪,獲取兩個future任務的返回結(jié)果竿滨,任何處理結(jié)果,沒有返回值
  3. runAfterBoth:組合兩個future辽旋,不需要獲取future的結(jié)果妓盲,只需要兩個future處理完任務后杂拨,處理該任務
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("執(zhí)行任務一");
    return 1;
}, executor);

CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("執(zhí)行任務二");
    return 2;
}, executor);

completableFuture1.runAfterBoth(completableFuture2, () -> {
    System.out.println("執(zhí)行任務三");
});

completableFuture1.thenCombineAsync(completableFuture2, (f1, f2) -> {
    int f3 = f1 + f2;
    System.out.println(f3);
    return f3;
}, executor);

組合任務--兩個任務完成一個,觸發(fā)該任務

  1. applyToEither:兩個任務有一個執(zhí)行完成悯衬,獲取它的返回值弹沽,處理任務并有新的返回值
  2. acceptEither:兩個任務有一個執(zhí)行完成,獲取它的返回值筋粗,處理任務策橘,沒有新的返回值
  3. runAfterEither:兩個任務有一個執(zhí)行完成,不需要獲取future的結(jié)果娜亿,處理任務丽已,也沒有返回值
completableFuture1.applyToEitherAsync(completableFuture2, (res) -> {
    System.out.println("執(zhí)行任務三");
    return res;
}, executor);

completableFuture1.acceptEitherAsync(completableFuture2, (res) -> {
    System.out.println("執(zhí)行任務三" + res);
}, executor);

completableFuture1.runAfterEitherAsync(completableFuture2, () -> {
    System.out.println("執(zhí)行任務三");
}, executor);

SpringBoot中使用線程池

  1. 定制線程池配置屬性
@ConfigurationProperties(prefix = "czs.thread")
@Configuration
@Data
public class ThreadPoolConfigProperties {
    // 核心線程數(shù)
    private Integer corePoolSize;
    // 最大線程數(shù)量
    private Integer maximumPoolSize;
    // 存活時間
    private Integer keepAliveTime;

}
  1. 配置線程池參數(shù)
czs.thread.core-pool-size=20
czs.thread.maximum-pool-size=200
czs.thread.keep-alive-time=10
  1. 將定制化線程池注入容器
@Configuration
public class MyThreadConfig {
    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
        return new ThreadPoolExecutor(pool.getCorePoolSize(), pool.getMaximumPoolSize(), pool.getKeepAliveTime(), TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市买决,隨后出現(xiàn)的幾起案子沛婴,更是在濱河造成了極大的恐慌吼畏,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘁灯,死亡現(xiàn)場離奇詭異泻蚊,居然都是意外死亡,警方通過查閱死者的電腦和手機旁仿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門藕夫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人枯冈,你說我怎么就攤上這事毅贮。” “怎么了尘奏?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵滩褥,是天一觀的道長。 經(jīng)常有香客問我炫加,道長瑰煎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任俗孝,我火速辦了婚禮酒甸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赋铝。我一直安慰自己插勤,他們只是感情好,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布革骨。 她就那樣靜靜地躺著农尖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪良哲。 梳的紋絲不亂的頭發(fā)上盛卡,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音筑凫,去河邊找鬼滑沧。 笑死,一個胖子當著我的面吹牛巍实,可吹牛的內(nèi)容都是我干的滓技。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蔫浆,長吁一口氣:“原來是場噩夢啊……” “哼殖属!你這毒婦竟也來了姐叁?” 一聲冷哼從身側(cè)響起瓦盛,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤洗显,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后原环,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挠唆,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年嘱吗,在試婚紗的時候發(fā)現(xiàn)自己被綠了玄组。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡谒麦,死狀恐怖俄讹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绕德,我是刑警寧澤患膛,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站耻蛇,受9級特大地震影響踪蹬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜臣咖,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一跃捣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧夺蛇,春花似錦疚漆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至截型,卻和暖如春趴荸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宦焦。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工发钝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人波闹。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓酝豪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親精堕。 傳聞我的和親對象是個殘疾皇子孵淘,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容