理解callable 和 spring deferredresult(翻译)-尊龙官方平台

理解callable 和 spring deferredresult(翻译)

el/2024/3/25 19:07:19

1-介绍

servlet 3中的异步支持为在另一个线程中处理http请求提供了可能性。当有一个长时间运行的任务时,这是特别有趣的,因为当另一个线程处理这个请求时,容器线程被释放,并且可以继续为其他请求服务。
这个主题已经解释了很多次,spring框架提供的关于这个功能的类似乎有一点混乱——在一个controller中返回callable 和 deferredresult。
在这篇文章中,我将实施这两个例子,以显示其差异。
这里所显示的所有示例都包括执行一个控制器,该控制器将执行一个长期运行的任务,然后将结果返回给客户机。长时间运行的任务由taskservice处理:

@service
public class taskserviceimpl implements taskservice {private final logger logger = loggerfactory.getlogger(this.getclass());@overridepublic string execute() {try {thread.sleep(5000);logger.info("slow task executed");return "task finished";} catch (interruptedexception e) {throw new runtimeexception();}}
}

这个web应用是用spring boot创建的,我们将执行下面的类来运行我们的例子:

@springbootapplication
public class mainapp {public static void main(string[] args) {springapplication.run(mainapp.class, args);}
}

2-阻塞的controller

在这个例子中,一个请求到达控制器。servlet线程不会被释放,直到长时间运行的方法被执行,我们退出@requestmapping注释的方法。

@restcontroller
public class blockingcontroller {private final logger logger = loggerfactory.getlogger(this.getclass());private final taskservice taskservice;@autowiredpublic blockingcontroller(taskservice taskservice) {this.taskservice = taskservice;}@requestmapping(value = "/block", method = requestmethod.get, produces = "text/html")public string executeslowtask() {logger.info("request received");string result = taskservice.execute();logger.info("servlet thread released");return result;}
}

如果我们运行这个例子http://localhost:8080/block,在日志里我们会发现servlet request不会被释放,直到长时间的任务执行完(5秒后)。

2015-07-12 12:41:11.849  [nio-8080-exec-6] x.s.web.controller.blockingcontroller    : request received
2015-07-12 12:41:16.851  [nio-8080-exec-6] x.spring.web.service.taskserviceimpl     : slow task executed
2015-07-12 12:41:16.851  [nio-8080-exec-6] x.s.web.controller.blockingcontroller    : servlet thread released

3-返回callable

在这个例子中,不是直接返回的结果,我们将返回一个callable:

@restcontroller
public class asynccallablecontroller {private final logger logger = loggerfactory.getlogger(this.getclass());private final taskservice taskservice;@autowiredpublic asynccallablecontroller(taskservice taskservice) {this.taskservice = taskservice;}@requestmapping(value = "/callable", method = requestmethod.get, produces = "text/html")public callable executeslowtask() {logger.info("request received");callable callable = taskservice::execute;logger.info("servlet thread released");return callable;}
}

返回callable意味着spring mvc将调用在不同的线程中执行定义的任务。spring将使用taskexecutor来管理线程。在等待完成的长期任务之前,servlet线程将被释放。

2015-07-12 13:07:07.012  [nio-8080-exec-5] x.s.w.c.asynccallablecontroller          : request received
2015-07-12 13:07:07.013  [nio-8080-exec-5] x.s.w.c.asynccallablecontroller          : servlet thread released
2015-07-12 13:07:12.014  [      mvcasync2] x.spring.web.service.taskserviceimpl     : slow task executed

你可以看到我们在长时间运行的任务执行完毕之前就已经从servlet返回了。这并不意味着客户端收到了一个响应。与客户端的通信仍然是开放的等待结果,但接收到的请求的线程已被释放,并可以服务于另一个客户的请求。

4-返回deferredresult

首先,我们需要创建一个deferredresult对象。此对象将由控制器返回。我们将完成和callable相同的事,当我们在另一个线程处理长时间运行的任务的时候释放servlet线程。

@restcontroller
public class asyncdeferredcontroller {private final logger logger = loggerfactory.getlogger(this.getclass());private final taskservice taskservice;@autowiredpublic asyncdeferredcontroller(taskservice taskservice) {this.taskservice = taskservice;}@requestmapping(value = "/deferred", method = requestmethod.get, produces = "text/html")public deferredresult executeslowtask() {logger.info("request received");deferredresult deferredresult = new deferredresult<>();completablefuture.supplyasync(taskservice::execute).whencompleteasync((result, throwable) -> deferredresult.setresult(result));logger.info("servlet thread released");return deferredresult;}
}

所以,返回deferredresult和返回callable有什么区别?不同的是这一次线程是由我们管理。创建一个线程并将结果set到deferredresult是由我们自己来做的。
用completablefuture创建一个异步任务。这将创建一个新的线程,在那里我们的长时间运行的任务将被执行。也就是在这个线程中,我们将set结果到deferredresult并返回。
是在哪个线程池中我们取回这个新的线程?默认情况下,在completablefuture的supplyasync方法将在forkjoin池运行任务。如果你想使用一个不同的线程池,你可以通过传一个executor到supplyasync方法:

public static <u> completablefuture<u> supplyasync(supplier<u> supplier, executor executor)

如果我们运行这个例子,我们将得到如下结果:

2015-07-12 13:28:08.433  [io-8080-exec-10] x.s.w.c.asyncdeferredcontroller          : request received
2015-07-12 13:28:08.475  [io-8080-exec-10] x.s.w.c.asyncdeferredcontroller          : servlet thread released
2015-07-12 13:28:13.469  [onpool-worker-1] x.spring.web.service.taskserviceimpl     : slow task executed 

5-结论

站在一定高度来看这问题,callable和deferredresult做的是同样的事情——释放容器线程,在另一个线程上异步运行长时间的任务。不同的是谁管理执行任务的线程。

文中涉及的代码spring-rest

翻译自xavier padró's blog

转自:http://www.cnblogs.com/aheizi/p/5659030.html


http://www.ngui.cc/el/5127680.html

相关文章

conflicts with existing, non-compatible bean definition of same name and class

使用 idea ce 创建的 maven web 项目,启动时却输出以下错误: connected to the target vm, address: 127.0.0.1:52165, transport: socket . ____ _ __ _ _ /\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | _ | _| | _ \/ …

使用eclipse中提供的refactor(重构)工具提取接口

最近用到网络编程方面的知识,在网上看到帖子 java nio的socket服务端编写 ,想跑一下提供的代码,但是在 eclipse 中创建了对应的类,把代码粘贴进去却发现少了一个接口 tcpprotocol 的定义。 代码如下: import java.io.ioexception; import java.nio.bytebuffer; import ja…

error: invalid byte sequence for encoding utf8: 0xd5 0xc5

在使用 psql 执行数据插入操作的时候,提示:error: invalid byte sequence for encoding "utf8": 0xd5 0xc5 错误原因是使用客户端工具 xshell 连接 ubuntu 系统时,没有指定编码为:utf-8 解决方法: 打开连…

c# 对象与json字符串互相转换的几种方式

随着 rest 风格 api 的应用越来越广泛,对象与json字符串互相转换的功能也用的越来越多。这里介绍三种方法,期中两种为dotnet framework .net 3.5 及后续版本自带的 datacontractjsonserializer、 javascriptserializer,另一种为 newtonsoft.j…

互联网传销来了!做为程序员你有免役力了吗?

进入社会几年的人应该都已经有免役力了, 最没有免役力的是那些学生,特别是刚走出校园急于找一份工作的学生。 是否还记得:程序员掉入传销组织 用代码“呼救”同事秒懂? 求职少年李文星之死:误入传销组织 不止李文星!又一青年死于天…

java.nio.channels.illegalblockingmodeexception

java.nio.channels.illegalblockingmodeexception 相关错误代码: [java] view plain copy class handler { public handler(selector selector, socketchannel socketchannel) throws interruptedexception { try { selec…

解决上传文件时 nginx 413 request entity too large 错误

一个使用tomcat 发布的站点,使用nginx做了代理,在上传文件时发生以下错误: 413 request entity too large

spring mvc环境中文件上传大小和文件类型限制以及超大文件上传bug问题

在上一篇文章中,主要介绍了spirng mvc环境下的正常情况下文件上传功能实现。在实际开发的时候,还会涉及到上传文件大小和类型的限制,接下来就会对spirng mvc环境下文件上传大小和类型的限制进行介绍,还会讲解到文件上传大小tomcat…

python web 框架 flask 入门 macos 下实践记录

flask是一个使用 python 编写的轻量级 web 应用框架。其 wsgi 工具箱采用 werkzeug ,模板引擎则使用 jinja2 ,使用 bsd 授权。 flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能。flask没有默…

改变你的文字 改变你的世界

改变你的文字 改变你的世界 这几个字说起来简单,但做起来是很难的。 表面上是改变文字, 而实质上是改变你的思维方式, 改变你的心态, 改变你看事物的角度。 视频中是不是有点夸张了呢? 改变几个文字的效果真的有那么大…
网站地图