我有一个需要50秒才能完成的大动作。 但是,与此同时,我还有另一个可以在服务器上处理的动作(点击链接)。
但是,如果我的第二个操作尝试访问我的第一个操作所放置的会话属性,那么它们会在第一个操作结束之前显示。
这是我的重大举措:
public String bigAction() {
HttpSession session = request.getSession();
synchronized (session) {
for(int i = 0 ; i < 100000 ; ++i)
session.setAttribute("foo_"+i, "bar");
}
return SUCCESS;
}
这是我的小动作:
public String smallAction() {
HttpSession session = request.getSession();
synchronized (session) {
session.getAttribute("foo_1", "bar");
}
return SUCCESS;
}
First action: ----------------------------------------------- Second action: --- -- --- - ---
因此,在这个例子中,我的第二个动作需要第一个动作创建的会话属性,但实际上它们不存在。
我如何同步会话?
答案 0 :(得分:2)
根据Servlet规范:
执行请求线程的多个servlet可以同时具有对同一会话对象的活动访问权限。容器必须确保以线程安全的方式执行表示会话属性的内部数据结构的操作。开发人员负责线程安全访问属性对象本身。这将保护HttpSession对象内的属性集合免于并发访问,从而消除了应用程序导致该集合损坏的机会。
这是安全的:
request.getSession().setAttribute("bar", "foo");
这不保证是安全的:
HttpSession session = request.getSession();
synchronized (session) {
String value = (String) session.getAttribute("bar");
}
此外,如果在同一个对象上,锁将起作用,不依赖于request.getSession()
返回相同的对象。 Servlet规范中没有任何内容表明每次请求时都无法将HttpServletSession
实例重新创建为外观对象。
阅读Java theory and practice: Are all stateful Web applications broken?和How HttpSession is not thread safe。
此处定义了一种方法,Java-synchronizing-on-transient-id。
答案 1 :(得分:0)
今天的变化:
我正在使用Struts 2,所以我实现了SessionAware,因为我读到它可能是一个很好的解决方案。但这是一样的。