我们可以把一个类的作用域注解为

@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 ,异步方法调用的更多相关文章

  1. ICE的异步方法调用

    转自:http://blog.sina.com.cn/s/blog_45497dfa0100nwbr.html http://www.cnblogs.com/mawanglin2008/article ...

  2. asyn4j -- java 异步方法调用框架

    asyn4j 是一个java异步方法调用框架,基于消费者与生产者模式.包括了异步方法执行,异步回调执行,异步工作缓存模块.支持Spring. 让我们写异步方法不再写很多的相关多线程代码.用asyn4j ...

  3. 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 ...

  4. Vue之状态管理(vuex)与接口调用

    Vue之状态管理(vuex)与接口调用 一,介绍与需求 1.1,介绍 1,状态管理(vuex) Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态 ...

  5. springboot(整合多数据源demo,aop,定时任务,异步方法调用,以及获取properties中自定义的变量值)

    有这么一个需求 每个部门,需要操作的数据库不同,A部门要将数据放test数据库,B 部门数据 要放在test1数据库 同一个项目 需要整合 多个数据源 上传个demo 方便自己以后回看!!!!!!!! ...

  6. Asynchronous_method_invocation 异步方法调用 让步 yielding

    zh.wikipedia.org/wiki/同步 [同步不同事件发生 时间一致] 同步(英语:Synchronization),指在一个系统中所发生的事件(event),之间进行协调,在时间上出现一致 ...

  7. spring@Async注解实现异步方法调用

    概述 如何实现异步方法调用,很多人首先会想到使用线程或者线程池技术,springboot中有一个很简单的方法可以实现异步方法调用,那就是在方法上使用@Async注解 例子 首先在Springboot启 ...

  8. C#多线程编程之:异步方法调用

    异步方法 当一个线程调用方法后,直到方法执行完毕,线程才继续执行,这种方法被称为同步方法.然而,有些方法执行时间可能非常长,比如串口操作或访问网络,这样线程被阻塞,而无法响应用户的其他请求.这种情况通 ...

  9. odoo开发笔记 -- 借助模块queue_job实现异步方法调用

    场景描述: 对比了几个定时调度的框架,发现各有优缺点: celery 很强,异步定时调度,异步周期调度,也有延时调度的功能,但是延时调度的案例比较少,遂暂时不使用. queue_job,一个odoo第 ...

随机推荐

  1. CentOS7 配置花生壳开机启动

    在家安装服务器,外地可以随时登陆,感觉花生壳特别方便,具体路由器配置请参考http://service.oray.com/question/2486.html. 我使用的操作系统是 [root@loc ...

  2. WebRoot 与 webContent的区别

    Web项目发布到Tomcat中. 在Eclipse中生成项目是WebContent目录 而在MyEclipse中生成的项目目录名字好像叫做WebRoot,那么如果把MyEclipse的项目导入到Ecl ...

  3. 异常org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 11; 注释中不允许出现字符串 "--"。的原因

    是由于编码格式不统一导致的. 把ecplise的workpace的编码改成utf-8

  4. Struts2如何搭建?

    如何搭建Struts2:   1.导入jar包 commons-fileupload-1.3.jar commons-io-2.0.1.jar commons-lang3-3.1.jar freema ...

  5. Codeforces D. Sorting the Coins

    D. Sorting the Coins time limit per test 1 second memory limit per test 512 megabytes input standard ...

  6. YII关联字段并带搜索排序功能

    1.简介 从接触yii框架到现在已经快有两个月了,但是自己对yii框架的了解程度并不是很深,并没有系统地去学习,仅仅只是在做项目的时候遇到不懂得知识才去翻手册. 在上一个项目中因为需要将关联的表的字段 ...

  7. C语言打印不出百分号'%'(以解决)

    1. 问题描述 今天,我需要把百分号'%'打印出来,考虑到它是特殊符号,我就用转义字符'\',和它组合,结果是漆黑的屏幕什么也没有. 2. 解决办法    我问度娘, 她告诉我要打印百分号需要在它的前 ...

  8. Win7系统下彻底删除无用服务的方法

    win7系统下中有非常多的服务项,用户来满足不同行业用户间的所有需求,系统服务也是执行指定系统功能的程序,许多情况下我们想要运行软件或执行外接设备都无法离开系统服务,但并非所有系统服务都是我们用到的, ...

  9. 使用py2exe发布windows平台Python

    一.简介 py2exe是一个将python脚本转换成windows上的可独立执行的可执行程序(*.exe)的工具,这样,你就可以不用装python而在windows系统上运行这个可执行程序.py2ex ...

  10. 创建一个vue项目的过程

    创建一个vue项目: 1.首先从UI手上拿到PSD设计图,然后看设计搞的内容,需要做个大概的页面布局 2.做vue之前不许安装node,因为做vue项目要和node结合使用 3.然后安装vue脚手架: ...