有状态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第 ...
随机推荐
- 自己模拟的一个简单的web服务器
首先我为大家推荐一本书:How Tomcat Works.这本书讲的很详细的,虽然实际开发中我们并不会自己去写一个tomcat,但是对于了解Tomcat是如何工作的还是很有必要的. Servlet容器 ...
- openvpn服务端与客户端网段互通
http://www.softown.cn/post/140.html OpenVPN安装.配置教程 http://www.softown.cn/post/137.html openvpn的serve ...
- linux判断文件是否存在
#!/bin/sh myPath="/var/log/httpd/" myFile="/var /log/httpd/access.log" # 这里的-x 参 ...
- SQL查询系列1---
1.查询关系为夫妻,年龄相加大于60的信息 表1 信息表 info id 编号 sex 性别 0-女,1-男 age 年龄 表2 关系表 rel id1 编号1 外键 id2 编号2 外键 r ...
- [C#] 《Concurrency in C# Cookbook》读书笔记(一)- 并发编程概述
并发编程概述 前言 我们经常在耳边听说一些关于高性能.并发和并行等名词,并且很多人都对并发编程有一些误解. 误解 1:并发就是多线程? 答:多线程只不过是并发编程的其中一种形式而已.并发编程的种类很多 ...
- SQL Server判断小数位数
项目中需要写一规则,目的是判断数值的小数位数,可以分为2中情况. 1.直接以小数点为分界点,小数点后的数据表示小数的位数,此种情况比较简单,直接使用CHARINDEX函数就可以搞定 其中CHARIND ...
- 玩转webpack(二):webpack的核心对象
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者介绍:陈柏信,腾讯前端开发,目前主要负责手Q游戏中心业务开发,以及项目相关的技术升级.架构优化等工作. 前言 webpack 是一个强大的模 ...
- 利用 secureCRT 直接上传下载文件 (sz,rz)
在window下向linux传送文件的方法. 首先在window中安装SecureCRT,然后在快速连接中建立一个到linux的连接,当然,你要先知道你的系统的ip,在终端中键入ifconfig可以查 ...
- Springboot security cas整合方案-原理篇
前言:网络中关于Spring security整合cas的方案有很多例,对于Springboot security整合cas方案则比较少,且有些仿制下来运行也有些错误,所以博主在此篇详细的分析cas原 ...
- Python基础篇(二)
Python最基本的数据结构是序列(sequence),序列中的每个元素被分以以0开头的唯一的一个id号. Python中有6种内建的序列:列表,元组,字符串,Unicode字符串,buffer对象和 ...