有状态InheritableThreadLocal 配合 JDK8 ,异步方法调用
我们可以把一个类的作用域注解为
@Scope(scopeName = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
这样这个类就能在session中获取,可以把用户信息放到这个类中,需要的时候,直接@Autowire进来就好了.
但是这样有一个坑.在主线程中,如果使用JDK异步方法,或者自己new出新的线程中,没有办法注入.会提示一个异常
Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;
这个异常非常误导人,在单线程下是不会提示的.提示了这个异常,原因是:session 是根据request获取的,那么Spring是用requestContextHolder实现的,原理还是InheritableThreadLocal ,按道理来说,在子线程也是可以获取到父线程的request.getSession,至于为什么在子线程中没有激活这个session作用域,导致注入失败,估计是Spring的设计问题.
所以参考RequestContextHolder,自己可以写一个记录结果以及错误信息的LocalResut
虽然我用了没有问题,但是所有书籍记录中,都不推荐在并发流或者多线程中使用有状态对象,虽然我这不涉及竞态条件,但是如果因为线程回收慢导致ThreadLocal数据没有回写到主线程就已经返回了,或者可见性问题,那么结果也会有误,而且不好debug
这里用一个ThreadLocal 记录结果集,或者错误信息,等调用完并发流以后,可以join之后,输出结果,注意线程可见性问题,这加上volatile 修饰.
public class LocalResult{
private static volatile ThreadLocal<Map<String, String>> mapMessage = new InheritableThreadLocal();
public LocalError() {
}
public static void mapMessageCreate() {
mapMessage.remove();
mapMessage.set(new HashMap());
}
public static ThreadLocal<Map<String, String>> getMapMessage() {
return mapMessage;
}
}
在这里根据订单的id数组,进行批量的异步结算,在结算方法中,如果有错误信息,依然会调用LocalResult,
线程池等于需要并发结算的数量+3 是一个容错,避免线程池的Thead不够,导致ThreadLocal数据乱套
for开启异步方法,之后马上关闭线程池
然后还要等待线程池所有线程已经回收以后才让方法返回:是因为线程执行完方法,不一定立即回收,当线程已经开启,马上调用线程池的shutdown方法,告诉线程执行完后,尽快回收.
然后循环判断线程池是否完全回收后,才返回因为,根据join()规则。假设线程A在执行的过程中,通过执行ThreadB.join()来等待线
程B终止;同时,假设线程B在终止之前修改了一些共享变量,线程A从ThreadB.join()返回后会
读这些共享变量。
.
public void doAsync(Integer [] ids) {
List<CompletableFuture<Boolean>> futures = new ArrayList<>(ids.length);
ExecutorService executor = Executors.newFixedThreadPool(ids.length+3);
for (Integer id : ids) {
Order order = orderService.findEntityById(id);
if (Order.Type.Failure.getCode().equals(orderInfo.getType())) {
LocalResult.getMapMessage().get().put(order.getOrderNo(), "单号:" + order.getOrderNo() + ",已作废,不能结算!");
continue;
}
futures.add(CompletableFuture.supplyAsync(() -> this.do(orderInfo),executor));
}
executor.shutdown();
futures.stream().map(CompletableFuture::join);
while (!executor.isTerminated()) {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
break;
}
}
}
controller
@PostMapping(path = "/do",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResultDataDto billing(@RequestParam("ids") Integer[] ids) {
LocalResult.mapMessageCreate();
service.doAsync(ids);
if (LocalResult.getMapMessage().get().size() > 0) {
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : LocalResult.getMapMessage().get().entrySet()) {
stringBuilder.append("单号:" + entry.getKey() + ":" + entry.getValue() + "</br>");
}
return ResultDataDto.addOperationSuccess("以下失败!:</br>" + stringBuilder.toString());
}
return ResultDataDto.addOperationSuccess("结算成功!");
}
有状态InheritableThreadLocal 配合 JDK8 ,异步方法调用的更多相关文章
- ICE的异步方法调用
转自:http://blog.sina.com.cn/s/blog_45497dfa0100nwbr.html http://www.cnblogs.com/mawanglin2008/article ...
- asyn4j -- java 异步方法调用框架
asyn4j 是一个java异步方法调用框架,基于消费者与生产者模式.包括了异步方法执行,异步回调执行,异步工作缓存模块.支持Spring. 让我们写异步方法不再写很多的相关多线程代码.用asyn4j ...
- JavaEE Tutorials (7) - 在会话bean中使用异步方法调用
7.1异步方法调用88 7.1.1创建异步业务方法88 7.1.2从企业bean客户端调用异步方法897.2async示例应用90 7.2.1async—war模块的架构91 7.2.2运行async ...
- Vue之状态管理(vuex)与接口调用
Vue之状态管理(vuex)与接口调用 一,介绍与需求 1.1,介绍 1,状态管理(vuex) Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态 ...
- springboot(整合多数据源demo,aop,定时任务,异步方法调用,以及获取properties中自定义的变量值)
有这么一个需求 每个部门,需要操作的数据库不同,A部门要将数据放test数据库,B 部门数据 要放在test1数据库 同一个项目 需要整合 多个数据源 上传个demo 方便自己以后回看!!!!!!!! ...
- Asynchronous_method_invocation 异步方法调用 让步 yielding
zh.wikipedia.org/wiki/同步 [同步不同事件发生 时间一致] 同步(英语:Synchronization),指在一个系统中所发生的事件(event),之间进行协调,在时间上出现一致 ...
- spring@Async注解实现异步方法调用
概述 如何实现异步方法调用,很多人首先会想到使用线程或者线程池技术,springboot中有一个很简单的方法可以实现异步方法调用,那就是在方法上使用@Async注解 例子 首先在Springboot启 ...
- C#多线程编程之:异步方法调用
异步方法 当一个线程调用方法后,直到方法执行完毕,线程才继续执行,这种方法被称为同步方法.然而,有些方法执行时间可能非常长,比如串口操作或访问网络,这样线程被阻塞,而无法响应用户的其他请求.这种情况通 ...
- odoo开发笔记 -- 借助模块queue_job实现异步方法调用
场景描述: 对比了几个定时调度的框架,发现各有优缺点: celery 很强,异步定时调度,异步周期调度,也有延时调度的功能,但是延时调度的案例比较少,遂暂时不使用. queue_job,一个odoo第 ...
随机推荐
- CentOS7 配置花生壳开机启动
在家安装服务器,外地可以随时登陆,感觉花生壳特别方便,具体路由器配置请参考http://service.oray.com/question/2486.html. 我使用的操作系统是 [root@loc ...
- WebRoot 与 webContent的区别
Web项目发布到Tomcat中. 在Eclipse中生成项目是WebContent目录 而在MyEclipse中生成的项目目录名字好像叫做WebRoot,那么如果把MyEclipse的项目导入到Ecl ...
- 异常org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 11; 注释中不允许出现字符串 "--"。的原因
是由于编码格式不统一导致的. 把ecplise的workpace的编码改成utf-8
- Struts2如何搭建?
如何搭建Struts2: 1.导入jar包 commons-fileupload-1.3.jar commons-io-2.0.1.jar commons-lang3-3.1.jar freema ...
- Codeforces D. Sorting the Coins
D. Sorting the Coins time limit per test 1 second memory limit per test 512 megabytes input standard ...
- YII关联字段并带搜索排序功能
1.简介 从接触yii框架到现在已经快有两个月了,但是自己对yii框架的了解程度并不是很深,并没有系统地去学习,仅仅只是在做项目的时候遇到不懂得知识才去翻手册. 在上一个项目中因为需要将关联的表的字段 ...
- C语言打印不出百分号'%'(以解决)
1. 问题描述 今天,我需要把百分号'%'打印出来,考虑到它是特殊符号,我就用转义字符'\',和它组合,结果是漆黑的屏幕什么也没有. 2. 解决办法 我问度娘, 她告诉我要打印百分号需要在它的前 ...
- Win7系统下彻底删除无用服务的方法
win7系统下中有非常多的服务项,用户来满足不同行业用户间的所有需求,系统服务也是执行指定系统功能的程序,许多情况下我们想要运行软件或执行外接设备都无法离开系统服务,但并非所有系统服务都是我们用到的, ...
- 使用py2exe发布windows平台Python
一.简介 py2exe是一个将python脚本转换成windows上的可独立执行的可执行程序(*.exe)的工具,这样,你就可以不用装python而在windows系统上运行这个可执行程序.py2ex ...
- 创建一个vue项目的过程
创建一个vue项目: 1.首先从UI手上拿到PSD设计图,然后看设计搞的内容,需要做个大概的页面布局 2.做vue之前不许安装node,因为做vue项目要和node结合使用 3.然后安装vue脚手架: ...