我写了一个小型的spring-mvc应用程序,以便更好地了解不同用户请求线程之间共享自动装配资源的方式。
我的控制器:
@Autowired
SharedResource sharedResource;
@RequestMapping(value = "/spring-sample/index",method= RequestMethod.GET)
public void index(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException{
RequestDispatcher dispatcher=request.getRequestDispatcher("/index.jsp");
request.setAttribute("value", sharedResource.accessme());
dispatcher.forward(request, response);
}
SharedResource.java:
@Service
public class SharedResource {
private Integer i;
public SharedResource(){
i=0;
}
public Integer accessme(){
int i=0;
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(SharedResource.class.getName()).log(Level.SEVERE, null, ex);
}
++i;
return i;
}
}
index.jsp
只打印返回的整数。
我打开了两个浏览器(例如,然后是chrome)并一个接一个地点击我的应用程序。
这是我走过代码的方式。
accessme
,将i
的值设置为0并进入休眠状态accessme
,将i
的值设置为0并进入睡眠状态i
的值增加到1并返回1 i
的值增加到2并返回2 所以,我希望即打印1
和chrome来打印2
但即打印1
然后打印铬1
这怎么可能?
尽管线程共享同一个对象并调用该对象,但似乎每个线程都有自己的方法副本,它共享对象的实例变量但每个都在自己的沙盒环境中运行。这是预期的行为吗?
如果我在某处发生了可怕的错误,请告诉我。
答案 0 :(得分:1)
您在i
方法中再次声明accessme
。此局部变量将覆盖该字段。
如果您希望这是多线程安全的,那么您应该使用AtomicInteger:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html
答案 1 :(得分:0)
所有bean默认情况下,Spring IOC容器中有singleton scopes
,因此不是线程安全的
您必须使用@Scope={"prototype"}
使其成为线程安全的
@Autowired
@Scope={"prototype"}
SharedResource sharedResource;
现在,对于每个请求,SharedResource
的新实例都是可用的