最近遇到一个了问题,简单的描述一下。
按模块调用接口,比如a、b、c、d四个模块每个模块2~3个接口,一笔交易最多四个模块,所以在调用时每个模块开启一个线程。那么问题来了模块线程在主线程中是通过注解自动注入的(模块线程依赖其他的bean,所以不能new),即模块线程单例的。
多线程环境下,把接口调用需要使用到的参数从主线程传到模块线程时,虽然在主线程中每一次都new一个新的参数,但因为模块线程是单例的,所以会有可能产生脏读的可能性(参数被其他线程覆盖掉了)
明确了问题后,解决方案是什么呢,当然对应的就是将单例的变成多例的。
通过上网查找后在模块线程的类加上注解
@Scope("prototype")
但是加上这个注解后并没有用(并不能多例),梳理了一下问题,当我在一个单例的类中通过@Autowired自动装配时,并不能产生多例的,原因@Autowired自动装配时,在spring容器中发现这个类的实例就会装配进取,所以并没有显式的创建新的实例。所以并不能在单例中这样创建多例。
//获取Spring上下文
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
ThreadModuleA module_A = wac.getBean("threadModuleA", ThreadModuleA.class);
这是一种不依赖于servlet,不需要注入的方式。但是需要注意一点,在服务器启动时,Spring容器初始化时,不能通过以下方法获取Spring 容器。
这样的话就可以创建多例了。
下面简单的放一下代码
主线程
reportBody = new ReportBody();
List<Task<ReportBody>> tasks = new ArrayList<Task<ReportBody>>();
Map<String, Object> map_report = new HashMap<String, Object>();
map_report.put("reportBody", reportBody);
// Body
//获取Spring上下文
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
if(reportType.contains(CommonEnum.THEMIS_DATA_A.getCode())){
map_report.put("paramsMap_base", paramsMap_base);
//获取对象,此操作可以获取多例对象(ThreadModuleA 需要配置@Scope("prototype"))
ThreadModuleA module_A = wac.getBean("threadModuleA", ThreadModuleA.class);
module_A.taskParams(map_report);
tasks.add(module_A);
}
if(reportType.contains(CommonEnum.THEMIS_DATA_B.getCode())){
map_report.put("paramsMap_base", paramsMap_base);
ThreadModuleB module_B = wac.getBean("threadModuleB", ThreadModuleB.class);
module_B.taskParams(map_report);
tasks.add(module_B);
}
if(reportType.contains(CommonEnum.THEMIS_DATA_C.getCode())) {
map_report.put("paramsMap_C", paramsMap_base);
ThreadModuleC module_C = wac.getBean("threadModuleC", ThreadModuleC.class);
module_C.taskParams(map_report);
tasks.add(module_C);
}
if(reportType.contains(CommonEnum.THEMIS_DATA_D.getCode())){
map_report.put("paramsMap_D", paramsMap_base);
ThreadModuleD module_D = wac.getBean("threadModuleD", ThreadModuleD.class);
module_D.taskParams(map_report);
tasks.add(module_D);
}
模块线程父类,赋值取值(其中Task继承了Callable)
public abstract class RunTask<T> implements Task<T>{
//传入参数
private Map<String, Object> params;
@Override
public void taskParams(Map<String, Object> params) {
this.params = params;
}
public Map<String, Object> getParams() {
return params;
}
}
模块线程
@Component
@Scope(“prototype”)
public class ThreadModuleA extends RunTask{
// 日志
private static Logger logger = LoggerFactory.getLogger(ThreadModuleA.class);
@Override
public ReportBody call() throws Exception {
// 初始化异步调用所需信息
//获取参数
Map<String, Object> map = this.getParams();
return reportBody;
}
}