先看一个简单的示例:

 @RequestMapping("/getFuture")
public Future<String> getFuture() {
System.out.println(1);
// 必须是ListenableFuture的子类,或者CompletionStage子类,或者是DeferredResult 不能是FutureTask
// 如何返回CompletableFuture
CompletableFuture<String> ftu2 = CompletableFuture.supplyAsync(() -> {
try {
// RequestContextHolder.setRequestAttributes(attributes);
// 使用ThreadLocal相关特性时,需要在外面先get
Thread.sleep(3000L);
} catch (InterruptedException e) {
} finally {
// RequestContextHolder.resetRequestAttributes();
}
return "THIS string";
}, es); //Future<String> future = executorService.submit(() -> { }); //返回值是FutureTask return ftu2;
}


客户端发起请求
===> DispatcherServlet根据返回值类型查找对应的handlar AsyncHandlerMethodReturnValueHandler
【Callable -->
CallableMethodReturnValueHandler; DeferredResult,CallableFuture,ListenableFuture --> DeferredResultMethodReturnValueHandler】
===> Controller中返回Future对象给容器, 
org.springframework.web.context.request.async.WebAsyncManager#startDeferredResultProcessing处理Future结果的监听 ===>
sleep3秒之后,Future完成后调用asyncWebRequest.dispatch() 重新发给Container,DispatcherServlet找到Message的序列化器将结果输出。DispatcherServlet.doService会进入两次!!!
异步线程的主要功能是: 
业务处理耗较长(上面的sleep3)时,可以先返回Future对象释放Container的work线程, work线程可以接收更多的请求。等Future完成之后重新调用Container的另一个work线程,输出response. 这里work线程可以是BIO中work线程, 也可以是NIO中work线程 不是所有的Future都能在异步线程中处理
https://www.cnblogs.com/dennyzhangdd/p/7010972.html spring boot中配置container的work线程数量
server.tomcat.max-threads=5
server.tomcat.min-spare-threads=3
 
使用异步处理的优点:
增加系统吞吐量,对响应速度提高不大,可能还会降低
缺点:
线程关系复杂, 异步超时、异常日志拦截需要实现具体的Adapter接口,threadLocal不好清理 参考:《亿级流量架构核心技术》http://jinnianshilongnian.iteye.com/blog/2245925
Servlet3.1 规范
    tomcat线程配置 https://www.cnblogs.com/kismetv/p/7806063.html
遗留问题: Future.get是什么时候调用的?
没有直接调用get。 ListenerableFuture, CompletableFuture任务完成之后都会触发回调 work1线程: 接收到请求---> DispatcherServlet--> return future -->WebAsyncManager#startDeferredResultProcessing
自定义的任务线程: CompletableFuture.postComplete之后调用 WebAsyncManager#setConcurrentResultAndDispatch
work2线程: dipatch ---> DispatcherServlet --> response.out 关于第二个任务线程
当返回值是Callable时,调用WebAsyncManager#startCallableProcessing, 此时任务线程使用的是AsyncTaskExecutor,
可以通过org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configureAsyncSupport设置自定义的AsyncTaskExecutor 当返回值是DeferredResult,ListenableFuture (Spring提供),CompletableFuture(JDK自带)时,调用WebAsyncManager#startDeferredResultProcessing,此时任务线程池可以直接指定
@See CompletableFuture.supply(xxxTask, threadPool)
@RequestMapping("/callableTest")
public Callable<String> callableTest() {
Callable<String> hello = () -> {
// 此处不能设置线程池, WebAsyncManager中会使用AsyncSupportConfigurer的线程池
System.out.println("===>" + Thread.currentThread().getName());
return "HELLO";
};
return hello;
}
												

最新文章

  1. ReadReadMe
  2. EF的入门使用 (电影管理)
  3. php比较时间戳与时间差计算函数( 实用)
  4. 从Java看跨平台的.NET需要些什么?
  5. SQL中CONVERT()函数用法详解
  6. [UNIX环境高级编程](第三版)中apue.h的问题
  7. 《JavaScript高级程序设计》 读书笔记(一)
  8. JBPM流程实例(PI)Process Instance
  9. 编写一个方法,输入DOM节点,返回包含所有父节点的一个数组
  10. TypeScript设计模式之组合、享元
  11. jmeter3.3测试需要登录的接口(java)
  12. MyBatis报错:Caused by: java.lang.NumberFormatException: For input string: &quot;XX&quot;
  13. java项目----衣服购买
  14. redis 系列11 列表对象
  15. IntelliJ IDEA 注册码——亲测有效
  16. NIO完成网络通信(一)
  17. Service Mesh简介
  18. Mysql root账号general_log_file方法获取webshell
  19. 小学四则运算APP 第一个冲刺阶段 第三天
  20. 【LOJ】#2128. 「HAOI2015」数字串拆分

热门文章

  1. 【总结整理】js获取css的属性(内部,外部,内嵌(写在tag中))
  2. Border Layout
  3. cd命令无效
  4. 【摘自张宴的&quot;实战:Nginx&quot;】使用nginx的proxy_cache模块替代squid,缓存静态文件
  5. C语言-郝斌笔记-006排序及查找
  6. oracle错误汇总解决
  7. Luogu 3466 [POI2008]KLO-Building blocks
  8. Bulma 源码解析之 .columns 类
  9. C++面试笔记--宏定义
  10. android studio 程序员有福了—从layout自动生成viewholder类