一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - 詳解Spring/Spring boot異步任務(wù)編程WebAsyncTask

詳解Spring/Spring boot異步任務(wù)編程WebAsyncTask

2021-05-09 14:27明人不說暗話___我喜歡你 Java教程

這篇文章主要介紹了詳解Spring/Spring boot異步任務(wù)編程WebAsyncTask,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

今天一起學習下如何在spring中進行異步編程。我們都知道,web服務(wù)器處理請求 request 的線程是從線程池中獲取的,這也不難解釋,因為當web請求并發(fā)數(shù)非常大時,如何一個請求進來就創(chuàng)建一條處理線程,由于創(chuàng)建線程和線程上下文切換的開銷是比較大的,web服務(wù)器最終將面臨崩潰。另外,web服務(wù)器創(chuàng)建的處理線程從頭到尾默認是同步執(zhí)行的,也就是說,假如處理線程a負責處理請求b,那么當b沒有 return 之前,處理線程a是不可以脫身去處理別的請求的,這將極大限制了web服務(wù)器的并發(fā)處理能力。

因此線程池解決了線程可循環(huán)利用的問題,那同步處理請求怎么去解決呢?答案是異步處理。什么是異步處理呢?異步處理主要是讓上面的b請求處理完成之前,能夠?qū)線程空閑出來繼續(xù)去處理別的請求。那么我們可以這樣做,在a線程內(nèi)部重新開啟一個線程c去執(zhí)行任務(wù),讓a直接返回給web服務(wù)器,繼續(xù)接受新進來的請求。

在開始下面的講解之前,我在這里先區(qū)別下兩個概念:

1、處理線程

處理線程屬于web服務(wù)器,負責處理用戶請求,采用線程池管理

2、異步線程

異步線程屬于用戶自定義的線程,可采用線程池管理

spring中提供了對異步任務(wù)的支持,采用 webasynctask 類即可實現(xiàn)異步任務(wù),同時我們也可以對異步任務(wù)設(shè)置相應(yīng)的回調(diào)處理,如當任務(wù)超時、拋出異常怎么處理等。異步任務(wù)通常非常實用,比如我們想讓一個可能會處理很長時間的操作交給異步線程去處理,又或者當一筆訂單支付完成之后,開啟異步任務(wù)查詢訂單的支付結(jié)果。

一、正常異步任務(wù)

為了演示方便,異步任務(wù)的執(zhí)行采用 thread.sleep(long) 模擬,現(xiàn)在假設(shè)用戶請求以下接口 :

http://localhost:7000/demo/getuserwithnothing.json

異步任務(wù)接口定義如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * 測試沒有發(fā)生任何異常的異步任務(wù)
 */
@requestmapping(value = "getuserwithnothing.json", method = requestmethod.get)
public webasynctask<string> getuserwithnothing() {
 // 打印處理線程名
 system.err.println("the main thread name is " + thread.currentthread().getname());
 
 // 此處模擬開啟一個異步任務(wù),超時時間為10s
 webasynctask<string> task1 = new webasynctask<string>(10 * 1000l, () -> {
    system.err.println("the first thread name is " + thread.currentthread().getname());
    // 任務(wù)處理時間5s,不超時
    thread.sleep(5 * 1000l);
    return "任務(wù)1順利執(zhí)行成功!任何異常都沒有拋出!";
 });
 
 // 任務(wù)執(zhí)行完成時調(diào)用該方法
 task1.oncompletion(() -> {
    system.err.println("任務(wù)1執(zhí)行完成啦!");
 });
 
 system.err.println("task1繼續(xù)處理其他事情!");
 return task1;
}

控制臺打印如下:

the main thread name is http-nio-7000-exec-1
task1繼續(xù)處理其他事情!
the first thread name is mvcasync1
任務(wù)1執(zhí)行完成啦!

瀏覽器結(jié)果如下:

 

 
詳解Spring/Spring boot異步任務(wù)編程WebAsyncTask 

 

二、拋異常異步任務(wù)

接口調(diào)用 : http://localhost:7000/demo/getuserwitherror.json

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * 測試發(fā)生error的異步任務(wù)
 * @return
 */
@requestmapping(value = "getuserwitherror.json", method = requestmethod.get)
public webasynctask<string> getuserwitherror() {
    system.err.println("the main thread name is " + thread.currentthread().getname());
 
    // 此處模擬開啟一個異步任務(wù)
    webasynctask<string> task3 = new webasynctask<string>(10 * 1000l, () -> {
        system.err.println("the second thread name is " + thread.currentthread().getname());
        // 此處拋出異常
        int num = 9 / 0;
        system.err.println(num);
        return "";
    });
 
    // 發(fā)生異常時調(diào)用該方法
    task3.onerror(() -> {
        system.err.println("====================================" + thread.currentthread().getname()
                + "==============================");
        system.err.println("任務(wù)3發(fā)生error啦!");
        return "";
    });
    // 任務(wù)執(zhí)行完成時調(diào)用該方法
    task3.oncompletion(() -> {
        system.err.println("任務(wù)3執(zhí)行完成啦!");
    });
 
    system.err.println("task3繼續(xù)處理其他事情!");
    return task3;
}

控制臺輸出如下:

the main thread name is http-nio-7000-exec-1
task3繼續(xù)處理其他事情!
the second thread name is mvcasync1
2018-06-15 09:40:13.538 error 9168 --- [nio-7000-exec-2] o.a.c.c.c.[.[.[.[dispatcherservlet] : servlet.service() for servlet [dispatcherservlet] threw exception

java.lang.arithmeticexception: / by zero
at com.example.demo.controller.getuserinfocontroller.lambda$5(getuserinfocontroller.java:93) ~[classes/:na]
at org.springframework.web.context.request.async.webasyncmanager.lambda$startcallableprocessing$4(webasyncmanager.java:317) ~[spring-web-5.0.6.release.jar:5.0.6.release]
at java.util.concurrent.executors$runnableadapter.call(executors.java:511) ~[na:1.8.0_161]
at java.util.concurrent.futuretask.run(futuretask.java:266) ~[na:1.8.0_161]
at java.lang.thread.run(thread.java:748) [na:1.8.0_161]

2018-06-15 09:40:13.539 error 9168 --- [nio-7000-exec-2] o.a.c.c.c.[.[.[.[dispatcherservlet] : servlet.service() for servlet [dispatcherservlet] in context with path [/demo] threw exception [request processing failed; nested exception is java.lang.arithmeticexception: / by zero] with root cause

java.lang.arithmeticexception: / by zero
at com.example.demo.controller.getuserinfocontroller.lambda$5(getuserinfocontroller.java:93) ~[classes/:na]
at org.springframework.web.context.request.async.webasyncmanager.lambda$startcallableprocessing$4(webasyncmanager.java:317) ~[spring-web-5.0.6.release.jar:5.0.6.release]
at java.util.concurrent.executors$runnableadapter.call(executors.java:511) ~[na:1.8.0_161]
at java.util.concurrent.futuretask.run(futuretask.java:266) ~[na:1.8.0_161]
at java.lang.thread.run(thread.java:748) [na:1.8.0_161]

====================================http-nio-7000-exec-2==============================
任務(wù)3發(fā)生error啦!
任務(wù)3執(zhí)行完成啦!

當然你也可以對上面做一些異常處理,不至于在用戶看來顯得不友好,關(guān)于異常處理,可以查看我的另一篇文章 spring boot/spring 統(tǒng)一錯誤處理方案的使用

瀏覽器輸出結(jié)果:

 

 
詳解Spring/Spring boot異步任務(wù)編程WebAsyncTask 

 

三、超時異步任務(wù)

接口調(diào)用 : http://localhost:7000/demo/getuserwithtimeout.json

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * 測試發(fā)生任務(wù)超時的異步任務(wù)
 * @return
 */
@requestmapping(value = "getuserwithtimeout.json", method = requestmethod.get)
public webasynctask<string> getuserwithtimeout() {
 system.err.println("the main thread name is " + thread.currentthread().getname());
 
 // 此處模擬開啟一個異步任務(wù),超時10s
 webasynctask<string> task2 = new webasynctask<string>(10 * 1000l, () -> {
    system.err.println("the second thread name is " + thread.currentthread().getname());
    thread.sleep(20 * 1000l);
    return "任務(wù)2執(zhí)行超時!";
 });
 
 // 任務(wù)超時調(diào)用該方法
 task2.ontimeout(() -> {
    system.err.println("====================================" + thread.currentthread().getname()
            + "==============================");
    return "任務(wù)2發(fā)生超時啦!";
 });
 
 // 任務(wù)執(zhí)行完成時調(diào)用該方法
 task2.oncompletion(() -> {
    system.err.println("任務(wù)2執(zhí)行完成啦!");
 });
 
 system.err.println("task2繼續(xù)處理其他事情!");
 return task2;
}

控制臺執(zhí)行結(jié)果:

the main thread name is http-nio-7000-exec-4
task2繼續(xù)處理其他事情!
the second thread name is mvcasync2
====================================http-nio-7000-exec-5==============================
任務(wù)2執(zhí)行完成啦!

瀏覽器執(zhí)行結(jié)果:

 

 
詳解Spring/Spring boot異步任務(wù)編程WebAsyncTask 

 

四、線程池異步任務(wù)

上面的三種情況中的異步任務(wù)默認不是采用線程池機制進行管理的,也就是說,一個請求進來,雖然釋放了處理線程,但是系統(tǒng)依舊會為每個請求創(chuàng)建一個異步任務(wù)線程,也就是上面我們看到的 mvcasync 開頭的異步任務(wù)線程,那這樣不行啊,開銷特別大呀!所以我們可以采用線程池進行管理,直接在 webasynctask 類構(gòu)造器傳入一個 threadpooltaskexecutor 對象實例即可。

下面我們先看看,當對上面第一種情況執(zhí)行并發(fā)請求時會出現(xiàn)什么情況(此處模擬對 http://localhost:7000/demo/getuserwithnothing.json 進行并發(fā)調(diào)用):

控制臺輸出如下:

the first thread name is mvcasync57
the first thread name is mvcasync58
the first thread name is mvcasync59
the first thread name is mvcasync60
the first thread name is mvcasync61
the first thread name is mvcasync62
the first thread name is mvcasync63
the first thread name is mvcasync64
the first thread name is mvcasync65
the first thread name is mvcasync66
the first thread name is mvcasync67
the first thread name is mvcasync68
the first thread name is mvcasync69
the first thread name is mvcasync70
the first thread name is mvcasync71
the first thread name is mvcasync72
the first thread name is mvcasync73
the first thread name is mvcasync74
the first thread name is mvcasync76
the first thread name is mvcasync75
the first thread name is mvcasync77
the first thread name is mvcasync78
the first thread name is mvcasync79
the first thread name is mvcasync80

由于沒有加入線程池,所以100個請求將開啟100個異步任務(wù)線程,開銷特別大,不推薦。

下面是采用線程池的實現(xiàn) :

調(diào)用接口 : http://localhost:7000/demo/getuserwithexecutor.json

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * 測試線程池
 * @return
 */
@requestmapping(value = "getuserwithexecutor.json", method = requestmethod.get)
public webasynctask<string> getuserwithexecutor() {
 system.err.println("the main thread name is " + thread.currentthread().getname());
 
 // 此處模擬開啟一個異步任務(wù),此處傳入一個線程池
 webasynctask<string> task1 = new webasynctask<string>(10 * 1000l, executor, () -> {
    system.err.println("the first thread name is " + thread.currentthread().getname());
    thread.sleep(5000l);
    return "任務(wù)4順利執(zhí)行成功!任何異常都沒有拋出!";
 });
 
 // 任務(wù)執(zhí)行完成時調(diào)用該方法
 task1.oncompletion(() -> {
    system.err.println("任務(wù)4執(zhí)行完成啦!");
 });
 
 system.err.println("task4繼續(xù)處理其他事情!");
 return task1;
}

線程池定義如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
@configuration
public class myexecutor {
 
 @bean
 public static threadpooltaskexecutor getexecutor() {
    threadpooltaskexecutor taskexecutor = new threadpooltaskexecutor();
    taskexecutor.setcorepoolsize(30);
    taskexecutor.setmaxpoolsize(30);
    taskexecutor.setqueuecapacity(50);
    taskexecutor.setthreadnameprefix("huang");// 異步任務(wù)線程名以 huang 為前綴
    return taskexecutor;
 }
}

對上面進行并發(fā)測試,可以得出下面結(jié)果 :

詳解Spring/Spring boot異步任務(wù)編程WebAsyncTask

本文示例代碼地址: https://github.com/smallercoder/webasynctask

采用線程池可以節(jié)約服務(wù)器資源,優(yōu)化服務(wù)器處理能力,要記得常用喲!謝謝閱讀!覺得對你有幫助,請給個start哦!

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://juejin.im/post/5b230edde51d4558bc58bc14

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲精品久久久久福利网站 | 亚洲va国产日韩欧美精品色婷婷 | 丰满岳乱妇在线观看视频国产 | 精品久久洲久久久久护士免费 | h杯奶水太多h | 欧美1| 大又大又黄又爽免费毛片 | 黑人异族日本人hd | mmkk在线看片 | 国产亚洲精品线观看77 | 啪啪艹| 欧美成人免费观看久久 | gay男男白袜chinese | 免费观看国产视频 | 久久99国产综合精品AV蜜桃 | 日本人成动漫网站在线观看 | 青青在线视频观看 | 日本啊v在线观看 | 好猛好紧好硬使劲好大刺激视频 | 国产3p绿奴在线视频 | chinesespank调教| 日本中文字幕高清 | 日日操日日舔 | chinese老太grandma | 男gay网站视频免费观看 | 啊哈~嗯哼~用力cao我小说 | 天堂bt在线| 久久99re2在线视频精品 | 丰满肥臀风间由美357在线 | 国内精品哆啪啪 | 91yellow吧字幕网zmff7 | 国产精品天天影视久久综合网 | 亚洲电影不卡 | bt天堂在线最新版在线 | 国产一级免费片 | 亚洲卡一卡2卡三卡4卡无卡三 | 亚洲成人第一页 | 美女任你模 | 日本韩国推理片免费观看网站 | 香蕉97超级碰碰碰免费公 | 国产精品成人网红女主播 |