日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
提高系統(tǒng)吞吐量,DeferredResult到底有多強(qiáng)?

大家都知道,Callable和DeferredResult?可以用來(lái)進(jìn)行異步請(qǐng)求處理。利用它們,我們可以異步生成返回值,在具體處理的過(guò)程中,我們直接在controller?中返回相應(yīng)的Callable?或者DeferredResult?,在這之后,servlet線(xiàn)程將被釋放,可用于其他連接;DeferredResult?另外會(huì)有線(xiàn)程來(lái)進(jìn)行結(jié)果處理,并setResult。

網(wǎng)站設(shè)計(jì)制作、網(wǎng)站設(shè)計(jì)介紹好的網(wǎng)站是理念、設(shè)計(jì)和技術(shù)的結(jié)合。創(chuàng)新互聯(lián)公司擁有的網(wǎng)站設(shè)計(jì)理念、多方位的設(shè)計(jì)風(fēng)格、經(jīng)驗(yàn)豐富的設(shè)計(jì)團(tuán)隊(duì)。提供PC端+手機(jī)端網(wǎng)站建設(shè),用營(yíng)銷(xiāo)思維進(jìn)行網(wǎng)站設(shè)計(jì)、采用先進(jìn)技術(shù)開(kāi)源代碼、注重用戶(hù)體驗(yàn)與SEO基礎(chǔ),將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶(hù)的方式做到創(chuàng)意性的視覺(jué)化效果。

基礎(chǔ)準(zhǔn)備

在正式開(kāi)始之前,我們先做一點(diǎn)準(zhǔn)備工作,在項(xiàng)目中新建了一個(gè)base模塊。其中包含一些提供基礎(chǔ)支持的java類(lèi),在其他模塊中可能會(huì)用到。

ResponseMsg

我們定義了一個(gè)ResponseMsg的實(shí)體類(lèi)來(lái)作為我們的返回值類(lèi)型:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResponseMsg {
private int code;
private String msg;
private T data;
}

非常簡(jiǎn)單,里面包含了code、msg和data三個(gè)字段,其中data為泛型類(lèi)型。另外類(lèi)的注解Data、NoArgsConstructor和AllArgsConstructor都是lombok提供的簡(jiǎn)化我們開(kāi)發(fā)的,主要功能分別是,為我們的類(lèi)生成set和get方法,生成無(wú)參構(gòu)造器和生成全參構(gòu)造器。使用idea進(jìn)行開(kāi)發(fā)的童鞋可以裝一下lombok的支持插件。另外,lombok的依賴(lài)參見(jiàn):


org.projectlombok
lombok-maven
1.16.16.0
pom

TaskService

我們建立了一個(gè)TaskService,用來(lái)為阻塞調(diào)用和Callable調(diào)用提供實(shí)際結(jié)果處理的。代碼如下:

@Service
public class TaskService {
private static final Logger log = LoggerFactory.getLogger(TaskService.class);
public ResponseMsg getResult(){
log.info("任務(wù)開(kāi)始執(zhí)行,持續(xù)等待中...");
try {
Thread.sleep(30000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("任務(wù)處理完成");
return new ResponseMsg(0,"操作成功","success");
}
}

可以看到,里面實(shí)際提供服務(wù)的是getResult方法,這邊直接返回一個(gè)new ResponseMsg(0,“操作成功”,“success”)。但是其中又特意讓它sleep了30秒,模擬一個(gè)耗時(shí)較長(zhǎng)的請(qǐng)求。

阻塞調(diào)用

平時(shí)我們用的最普遍的還是阻塞調(diào)用,通常請(qǐng)求的處理時(shí)間較短,在并發(fā)量較小的情況下,使用阻塞調(diào)用問(wèn)題也不是很大。關(guān)注公眾號(hào):碼猿技術(shù)專(zhuān)欄,回復(fù)關(guān)鍵詞:1111 獲取阿里內(nèi)部Java性能調(diào)優(yōu)手冊(cè)!阻塞調(diào)用實(shí)現(xiàn)非常簡(jiǎn)單,我們首先新建一個(gè)模塊blockingtype?,里面只包含一個(gè)controller?類(lèi),用來(lái)接收請(qǐng)求并利用TaskService來(lái)獲取結(jié)果。

@RestController
public class BlockController {
private static final Logger log = LoggerFactory.getLogger(BlockController.class);
@Autowired
private TaskService taskService;
@RequestMapping(value = "/get", method = RequestMethod.GET)
public ResponseMsg getResult(){
log.info("接收請(qǐng)求,開(kāi)始處理...");
ResponseMsg result = taskService.getResult();
log.info("接收任務(wù)線(xiàn)程完成并退出");
return result;
}
}

我們請(qǐng)求的是getResult?方法,其中調(diào)用了taskService?,這個(gè)taskService?我們是注入得到的。關(guān)于怎么跨模塊注入的,其實(shí)也非常簡(jiǎn)單,在本模塊,加入對(duì)其他模塊的依賴(lài)就可以了。比如這里我們?cè)赽lockingtype的pom.xml文件中加入對(duì)base模塊的依賴(lài):


com.sunny
base
1.0-SNAPSHOT

然后我們看一下實(shí)際調(diào)用效果,這里我們?cè)O(shè)置端口號(hào)為8080,啟動(dòng)日志如下:

2018-06-24 19:02:48.514  INFO 11207 --- [           main] com.sunny.BlockApplication               : Starting BlockApplication on xdeMacBook-Pro.local with PID 11207 (/Users/zsunny/IdeaProjects/asynchronoustask/blockingtype/target/classes started by zsunny in /Users/zsunny/IdeaProjects/asynchronoustask)
2018-06-24 19:02:48.519 INFO 11207 --- [ main] com.sunny.BlockApplication : No active profile set, falling back to default profiles: default
2018-06-24 19:02:48.762 INFO 11207 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4445629: startup date [Sun Jun 24 19:02:48 CST 2018]; root of context hierarchy
2018-06-24 19:02:50.756 INFO 11207 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-06-24 19:02:50.778 INFO 11207 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2018-06-24 19:02:50.780 INFO 11207 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.23
2018-06-24 19:02:50.922 INFO 11207 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-06-24 19:02:50.922 INFO 11207 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2200 ms
2018-06-24 19:02:51.156 INFO 11207 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2018-06-24 19:02:51.162 INFO 11207 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-06-24 19:02:51.163 INFO 11207 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-06-24 19:02:51.163 INFO 11207 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-06-24 19:02:51.163 INFO 11207 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2018-06-24 19:02:51.620 INFO 11207 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4445629: startup date [Sun Jun 24 19:02:48 CST 2018]; root of context hierarchy
2018-06-24 19:02:51.724 INFO 11207 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/get],methods=[GET]}" onto public com.sunny.entity.ResponseMsg com.sunny.controller.BlockController.getResult()
2018-06-24 19:02:51.730 INFO 11207 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-06-24 19:02:51.731 INFO 11207 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-06-24 19:02:51.780 INFO 11207 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-24 19:02:51.780 INFO 11207 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-24 19:02:51.838 INFO 11207 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-24 19:02:52.126 INFO 11207 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-06-24 19:02:52.205 INFO 11207 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-06-24 19:02:52.211 INFO 11207 --- [ main] com.sunny.BlockApplication : Started BlockApplication in 5.049 seconds (JVM running for 6.118)

可以看到順利啟動(dòng)了,那么我們就來(lái)訪(fǎng)問(wèn)一下:

http://localhost:8080/get

等待了大概30秒左右,得到j(luò)son數(shù)據(jù):

{"code":0,"msg":"操作成功","data":"success"}

然后我們來(lái)看看控制臺(tái)的日志:

2018-06-24 19:04:07.315  INFO 11207 --- [nio-8080-exec-1] com.sunny.controller.BlockController     : 接收請(qǐng)求,開(kāi)始處理...
2018-06-24 19:04:07.316 INFO 11207 --- [nio-8080-exec-1] com.sunny.service.TaskService : 任務(wù)開(kāi)始執(zhí)行,持續(xù)等待中...
2018-06-24 19:04:37.322 INFO 11207 --- [nio-8080-exec-1] com.sunny.service.TaskService : 任務(wù)處理完成
2018-06-24 19:04:37.322 INFO 11207 --- [nio-8080-exec-1] com.sunny.controller.BlockController : 接收任務(wù)線(xiàn)程完成并退出

可以看到在“ResponseMsg result = taskService.getResult();?”的時(shí)候是阻塞了大約30秒鐘,隨后才執(zhí)行它后面的打印語(yǔ)句“l(fā)og.info(“接收任務(wù)線(xiàn)程完成并退出”);”。

Callable異步調(diào)用

涉及到較長(zhǎng)時(shí)間的請(qǐng)求處理的話(huà),比較好的方式是用異步調(diào)用,比如利用Callable?返回結(jié)果。異步主要表現(xiàn)在,接收請(qǐng)求的servlet?可以不用持續(xù)等待結(jié)果產(chǎn)生,而可以被釋放去處理其他事情。當(dāng)然,在調(diào)用者來(lái)看的話(huà),其實(shí)還是表現(xiàn)在持續(xù)等待30秒。這有利于服務(wù)端提供更大的并發(fā)處理量。這里我們新建一個(gè)callabledemo?模塊,在這個(gè)模塊中,我們一樣只包含一個(gè)TaskController?,另外也是需要加入base模塊的依賴(lài)。只不過(guò)這里我們的返回值不是ResponseMsg?類(lèi)型了,而是一個(gè)Callable類(lèi)型。

@RestController
public class TaskController {
private static final Logger log = LoggerFactory.getLogger(TaskController.class);

@Autowired
private TaskService taskService;

@RequestMapping(value = "/get",method = RequestMethod.GET)
public Callable> getResult(){

log.info("接收請(qǐng)求,開(kāi)始處理...");

Callable> result = (()->{
return taskService.getResult();
});

log.info("接收任務(wù)線(xiàn)程完成并退出");
return result;
}
}

在里面,我們創(chuàng)建了一個(gè)Callable?類(lèi)型的變量result,并實(shí)現(xiàn)了它的call方法,在call方法中,我們也是調(diào)用taskService的getResult?方法得到返回值并返回。下一步我們就運(yùn)行一下這個(gè)模塊,這里我們?cè)谀K的application.yml中設(shè)置端口號(hào)為8081:

server:
port: 8081

啟動(dòng),可以看到控制臺(tái)的消息:

2018-06-24 19:38:14.658  INFO 11226 --- [           main] com.sunny.CallableApplication            : Starting CallableApplication on xdeMacBook-Pro.local with PID 11226 (/Users/zsunny/IdeaProjects/asynchronoustask/callabledemo/target/classes started by zsunny in /Users/zsunny/IdeaProjects/asynchronoustask)
2018-06-24 19:38:14.672 INFO 11226 --- [ main] com.sunny.CallableApplication : No active profile set, falling back to default profiles: default
2018-06-24 19:38:14.798 INFO 11226 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4445629: startup date [Sun Jun 24 19:38:14 CST 2018]; root of context hierarchy
2018-06-24 19:38:16.741 INFO 11226 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8081 (http)
2018-06-24 19:38:16.762 INFO 11226 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2018-06-24 19:38:16.764 INFO 11226 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.23
2018-06-24 19:38:16.918 INFO 11226 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-06-24 19:38:16.919 INFO 11226 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2126 ms
2018-06-24 19:38:17.144 INFO 11226 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2018-06-24 19:38:17.149 INFO 11226 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-06-24 19:38:17.150 INFO 11226 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-06-24 19:38:17.150 INFO 11226 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-06-24 19:38:17.150 INFO 11226 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2018-06-24 19:38:17.632 INFO 11226 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4445629: startup date [Sun Jun 24 19:38:14 CST 2018]; root of context hierarchy
2018-06-24 19:38:17.726 INFO 11226 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/get],methods=[GET]}" onto public java.util.concurrent.Callable> com.sunny.controller.TaskController.getResult()
2018-06-24 19:38:17.731 INFO 11226 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-06-24 19:38:17.733 INFO 11226 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-06-24 19:38:17.777 INFO 11226 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-24 19:38:17.777 INFO 11226 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-24 19:38:17.825 INFO 11226 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-24 19:38:18.084 INFO 11226 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-06-24 19:38:18.176 INFO 11226 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8081 (http)
2018-06-24 19:38:18.183 INFO 11226 --- [ main] com.sunny.CallableApplication : Started CallableApplication in 4.538 seconds (JVM running for 5.327)

完美啟動(dòng)了,然后我們還是一樣,訪(fǎng)問(wèn)一下:

http://localhost:8081/get

在大約等待了30秒左右,我們?cè)跒g覽器上得到j(luò)son數(shù)據(jù):

{"code":0,"msg":"操作成功","data":"success"}

和阻塞調(diào)用的結(jié)果一樣——當(dāng)然一樣啦,都是同taskService中得到的結(jié)果。然后我們看看控制臺(tái)的消息:

2018-06-24 19:39:07.738  INFO 11226 --- [nio-8081-exec-1] com.sunny.controller.TaskController      : 接收請(qǐng)求,開(kāi)始處理...
2018-06-24 19:39:07.740 INFO 11226 --- [nio-8081-exec-1] com.sunny.controller.TaskController : 接收任務(wù)線(xiàn)程完成并退出
2018-06-24 19:39:07.753 INFO 11226 --- [ MvcAsync1] com.sunny.service.TaskService : 任務(wù)開(kāi)始執(zhí)行,持續(xù)等待中...
2018-06-24 19:39:37.756 INFO 11226 --- [ MvcAsync1] com.sunny.service.TaskService : 任務(wù)處理完成

很顯然,這里的消息出現(xiàn)的順序和阻塞模式有所不同了,這里在“接收請(qǐng)求,開(kāi)始處理…”之后直接打印了“接收任務(wù)線(xiàn)程完成并退出”。而不是先出現(xiàn)“任務(wù)處理完成”后再出現(xiàn)“接收任務(wù)線(xiàn)程完成并退出”。這就說(shuō)明,這里沒(méi)有阻塞在從taskService?中獲得數(shù)據(jù)的地方,controller中直接執(zhí)行后面的部分(這里可以做其他很多事,不僅僅是打印日志)。

DeferredResult異步調(diào)用

前面鋪墊了那么多,還是主要來(lái)說(shuō)DeferredResult?的;和Callable?一樣,DeferredResult?也是為了支持異步調(diào)用。兩者的主要差異,Sunny覺(jué)得主要在DeferredResult?需要自己用線(xiàn)程來(lái)處理結(jié)果setResult?,而Callable?的話(huà)不需要我們來(lái)維護(hù)一個(gè)結(jié)果處理線(xiàn)程??傮w來(lái)說(shuō),Callable?的話(huà)更為簡(jiǎn)單,同樣的也是因?yàn)楹?jiǎn)單,靈活性不夠;相對(duì)地,DeferredResult?更為復(fù)雜一些,但是又極大的靈活性。在可以用Callable?的時(shí)候,直接用Callable?;而遇到Callable?沒(méi)法解決的場(chǎng)景的時(shí)候,可以嘗試使用DeferredResult?。這里Sunny將會(huì)設(shè)計(jì)兩個(gè)DeferredResult使用場(chǎng)景。

場(chǎng)景一:
  • 創(chuàng)建一個(gè)持續(xù)在隨機(jī)間隔時(shí)間后從任務(wù)隊(duì)列中獲取任務(wù)的線(xiàn)程
  • 訪(fǎng)問(wèn)controller中的方法,創(chuàng)建一個(gè)DeferredResult,設(shè)定超時(shí)時(shí)間和超時(shí)返回對(duì)象
  • 設(shè)定DeferredResult的超時(shí)回調(diào)方法和完成回調(diào)方法
  • 將DeferredResult放入任務(wù)中,并將任務(wù)放入任務(wù)隊(duì)列
  • 步驟1中的線(xiàn)程獲取到任務(wù)隊(duì)列中的任務(wù),并產(chǎn)生一個(gè)隨機(jī)結(jié)果返回
  • 場(chǎng)景其實(shí)非常簡(jiǎn)單,接下來(lái)我們來(lái)看看具體的實(shí)現(xiàn)。首先,我們還是來(lái)看任務(wù)實(shí)體類(lèi)是怎么樣的。
/**
* 任務(wù)實(shí)體類(lèi)
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Task {
private int taskId;
private DeferredResult> taskResult;

@Override
public String toString() {
return "Task{" +
"taskId=" + taskId +
", taskResult" + "{respnotallow=" + taskResult.getResult() + "}" +
'}';
}
}

看起來(lái)非常簡(jiǎn)單,成員變量又taskId和taskResult?,前者是int類(lèi)型,后者為我們的DeferredResult?類(lèi)型,它的泛型類(lèi)型為ResponseMsg?,注意這里用到ResponseMsg?,所以也需要導(dǎo)入base模塊的依賴(lài)。另外注解之前已經(jīng)說(shuō)明了,不過(guò)這里再提一句,@Data?注解也包含了toString的重寫(xiě),但是這里為了知道具體的ResponseMsg的內(nèi)容,Sunny特意手動(dòng)重寫(xiě)??赐闠ask類(lèi)型,我們?cè)賮?lái)看看任務(wù)隊(duì)列。

@Component
public class TaskQueue {
private static final Logger log = LoggerFactory.getLogger(TaskQueue.class);
private static final int QUEUE_LENGTH = 10;
private BlockingQueue queue = new LinkedBlockingDeque<>(QUEUE_LENGTH);
private int taskId = 0;
/**
* 加入任務(wù)
* @param deferredResult
*/
public void put(DeferredResult> deferredResult){

taskId++;
log.info("任務(wù)加入隊(duì)列,id為:{}",taskId);
queue.offer(new Task(taskId,deferredResult));
}

/**
* 獲取任務(wù)
* @return
* @throws InterruptedException
*/
public Task take() throws InterruptedException {
Task task = queue.poll();
log.info("獲得任務(wù):{}",task);
return task;
}
}

這里我們將它作為一個(gè)bean,之后會(huì)在其他bean中注入,這里實(shí)際的隊(duì)列為成員變量queue,它是LinkedBlockingDeque?類(lèi)型的。還有一個(gè)成員變量為taskId,是用于自動(dòng)生成任務(wù)id的,并且在加入任務(wù)的方法中實(shí)現(xiàn)自增,以確保每個(gè)任務(wù)的id唯一性。方法的話(huà)又put和take方法,分別用于向隊(duì)列中添加任務(wù)和取出任務(wù);其中,對(duì)queue的操作,分別用了offer和poll,這樣是實(shí)現(xiàn)一個(gè)非阻塞的操作,并且在隊(duì)列為空和隊(duì)列已滿(mǎn)的情況下不會(huì)拋出異常。另外,大家實(shí)現(xiàn)的時(shí)候,可以考慮使用ConcurrentLinkedQueue?來(lái)高效處理并發(fā),因?yàn)樗鼘儆跓o(wú)界非阻塞隊(duì)列,使用過(guò)程中需要考慮可能造成的OOM問(wèn)題。Sunny這里選擇阻塞隊(duì)列LinkedBlockingDeque?,它底層使用加鎖進(jìn)行了同步;但是這里使用了TaskQueue進(jìn)行封裝,處理過(guò)程中有一些額外操作,調(diào)用時(shí)需要加鎖以防發(fā)生某些意料之外的問(wèn)題。

然后我們來(lái)看步驟1中的,啟動(dòng)一個(gè)持續(xù)從任務(wù)隊(duì)列中獲取任務(wù)的線(xiàn)程的具體實(shí)現(xiàn)。

@Component
public class TaskExecute {
private static final Logger log = LoggerFactory.getLogger(TaskExecute.class);
private static final Random random = new Random();

//默認(rèn)隨機(jī)結(jié)果的長(zhǎng)度
private static final int DEFAULT_STR_LEN = 10;

//用于生成隨機(jī)結(jié)果
private static final String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

@Autowired
private TaskQueue taskQueue;
/**
* 初始化啟動(dòng)
*/
@PostConstruct
public void init(){
log.info("開(kāi)始持續(xù)處理任務(wù)");
new Thread(this::execute).start();
}

/**
* 持續(xù)處理
* 返回執(zhí)行結(jié)果
*/
private void execute(){
while (true){
try {
//取出任務(wù)
Task task;
synchronized (taskQueue) {
task = taskQueue.take();

}

if(task != null) {

//設(shè)置返回結(jié)果
String randomStr = getRandomStr(DEFAULT_STR_LEN);
ResponseMsg responseMsg = new ResponseMsg(0, "success", randomStr);
log.info("返回結(jié)果:{}", responseMsg);
task.getTaskResult().setResult(responseMsg);
}
int time = random.nextInt(10);
log.info("處理間隔:{}秒",time);
Thread.sleep(time*1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 獲取長(zhǎng)度為len的隨機(jī)串
* @param len
* @return
*/
private String getRandomStr(int len){
int maxInd = str.length();
StringBuilder sb = new StringBuilder();
int ind;

for(int i=0;i ind = random.nextInt(maxInd);
sb.append(str.charAt(ind));
}
return String.valueOf(sb);
}
}

這里,我們注入了TaskQueue?,成員變量比較簡(jiǎn)單并且有注釋?zhuān)辉僬f(shuō)明,主要來(lái)看方法。先看一下最后一個(gè)方法getRandomStr?,很顯然,這是一個(gè)獲得長(zhǎng)度為len的隨機(jī)串的方法,訪(fǎng)問(wèn)限定為private,為類(lèi)中其他方法服務(wù)的。然后我們看init方法,它執(zhí)行的其實(shí)就是開(kāi)啟了一個(gè)線(xiàn)程并且執(zhí)行execute方法,注意一下它上面的@PostContruct?注解,這個(gè)注解就是在這個(gè)bean初始化的時(shí)候就執(zhí)行這個(gè)方法。所以我們需要關(guān)注的實(shí)際邏輯在execute?方法中??梢钥吹剑趀xecute?方法中,用了一個(gè)while(true)?來(lái)保證線(xiàn)程持續(xù)運(yùn)行。因?yàn)槭遣l(fā)環(huán)境下,考慮對(duì)taskQueue?加鎖,從中取出任務(wù);如果任務(wù)不為空,獲取用getRandomStr?生成一個(gè)隨機(jī)結(jié)果并用setResult?方法進(jìn)行返回。最后可以看到,利用random生成來(lái)一個(gè)[0,10)?的隨機(jī)數(shù),并讓線(xiàn)程sleep相應(yīng)的秒數(shù)。這里注意一下,需要設(shè)定一個(gè)時(shí)間間隔,否則,先線(xiàn)程持續(xù)跑會(huì)出現(xiàn)CPU負(fù)載過(guò)高的情況。接下來(lái)我們就看看controller是如何處理的。

@RestController
public class TaskController {
private static final Logger log = LoggerFactory.getLogger(TaskController.class);

//超時(shí)結(jié)果
private static final ResponseMsg OUT_OF_TIME_RESULT = new ResponseMsg<>(-1,"超時(shí)","out of time");

//超時(shí)時(shí)間
private static final long OUT_OF_TIME = 3000L;

@Autowired
private TaskQueue taskQueue;

@RequestMapping(value = "/get",method = RequestMethod.GET)
public DeferredResult> getResult() {

log.info("接收請(qǐng)求,開(kāi)始處理...");

//建立DeferredResult對(duì)象,設(shè)置超時(shí)時(shí)間,以及超時(shí)返回超時(shí)結(jié)果
DeferredResult> result = new DeferredResult<>(OUT_OF_TIME, OUT_OF_TIME_RESULT);

result.onTimeout(() -> {
log.info("調(diào)用超時(shí)");
});

result.onCompletion(() -> {

網(wǎng)站名稱(chēng):提高系統(tǒng)吞吐量,DeferredResult到底有多強(qiáng)?
當(dāng)前地址:http://www.dlmjj.cn/article/ccicegd.html