首页 > 代码库 > Spring MVC 线程安全问题的思考

Spring MVC 线程安全问题的思考

Spring MVC 线程安全问题的思考

在读一些博文的时候发现有些文章对SpringMVC的Controller线程安全的验证并不正确,比如没有探究controller线程不安全的具体原因,比如将请求线程当做controller多例的证明,以下将验证。
http://bbs.csdn.net/topics/390894585
http://bbs.csdn.net/topics/390891861#post-398241838

 

1.request请求线程与controllte的关系是什么?

简易的验证方法代码

技术分享

在网上随便下载了一个压力测试工具

技术分享

测试结果如下

技术分享

 

从打印的日志可以看出,请求时多线程请求的,但是每次请求过来调用的Controller对象都是一个,而不是一个请求过来就创建一个controller对象

那为什么说controller是不安全的呢?

原因就在于如果这个controller对象是单例的,那么如果不小心在类中定义了类变量,那么这个类变量是被所有请求共享的,这可能会造成多个请求修改该变量的值,出现与预期结果不符合的异常。

接下来将验证多并发的情况下controller的线程不安全的具体表现、通过配置实现controller多例

在单例的情况下 相当于所有类变量对于每次请求都是共享的,每一次请求对类变量的修改都是有效的

 

[java] view plain copy
 
 技术分享技术分享
  1. private static int st=0;  
  2. private int index=0;  
  3. @RequestMapping(value=http://www.mamicode.com/"/testcontrollersinglon",method=RequestMethod.GET)  
  4.     @ResponseBody  
  5.     public String testControllerSinglon(HttpServletRequest request){  
  6.         try {  
  7.             System.out.println(st++ + " | " + index++);  
  8.             return "yes";  
  9.         } catch (Exception e) {  
  10.             e.printStackTrace();  
  11.             return "error";  
  12.         }  
  13.     }  

看一下打印的日志

 


技术分享

通过日志可以看出 变量index为所有请求共享 

那有没有办法让controller不以单例而以每次请求都重新创建的形式存在呢?

答案是当然可以,只需要在类上添加注解@Scope("prototype")即可,这样每次请求调用的类都是重新生成的(每次生成会影响效率)

添加@Scope("prototype")后我们再看看日志就会看出区别了

技术分享

虽然这样可以解决问题,但增加了时间成本,总让人不爽,还有其他方法么?答案是肯定的!使用ThreadLocal 来保存类变量,将类变量保存在线程的变量域中,让不同的请求隔离开来

Spring MVC 线程安全问题的思考