Spring MVC - 线程如何共享自动装配的资源

时间:2013-12-06 09:28:31

标签: spring-mvc

我写了一个小型的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)并一个接一个地点击我的应用程序。

这是我走过代码的方式。

  1. Thread1(来自ie的请求)调用accessme,将i的值设置为0并进入休眠状态
  2. Thread2(来自chrome的请求)调用accessme,将i的值设置为0并进入睡眠状态
  3. Thread1唤醒,将i的值增加到1并返回1
  4. Thread2唤醒,将i的值增加到2并返回2
  5. 所以,我希望即打印1和chrome来打印2

    但即打印1然后打印铬1

    这怎么可能?

    尽管线程共享同一个对象并调用该对象,但似乎每个线程都有自己的方法副本,它共享对象的实例变量但每个都在自己的沙盒环境中运行。这是预期的行为吗?

    如果我在某处发生了可怕的错误,请告诉我。

2 个答案:

答案 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的新实例都是可用的