【问题标题】:Is HttpSessionAttributeListener processed async?HttpSessionAttributeListener 是异步处理的吗?
【发布时间】:2016-01-21 08:58:49
【问题描述】:
考虑算法:
- 一个新属性被添加到会话
session.setAttribute("myObject", new Object);
-
HttpSessionAttributeListener#attributeAdded 被调用
-
session.setAttribute 之后的代码
HttpSessionAttributeListener#attributeAdded 是否阻塞 session.setAttribute 或侦听器代码调用异步?
【问题讨论】:
标签:
java
session
servlets
listener
【解决方案1】:
在调用set|get|removeAttribute() 的同一线程中调用侦听器。
因此,当在另一个线程中调用 setAttribute() 时,可能会发生唯一的竞争条件。鉴于一般的 servlet 容器使用 single thread per HTTP connection(因此当 HTTP 1.1 keep-alive 开启时不一定每个 HTTP 请求),那么当最终用户产生两个完全独立的浏览器实例(不是窗口/选项卡)时,可能会发生这种竞争情况并将会话 cookie 从一个复制到另一个,然后同时从该会话上的两个客户端触发请求,从而触发服务器中的 setAttribute() 方法。
然而,这不是一个常见的现实世界案例。此外,容器本身会担心访问HttpSession 实例的线程安全性。这在Servlet specification(强调我的)的第 7.7.1 章中有规定:
7.7.1 线程问题
执行请求线程的多个 servlet 可以对同一个线程进行主动访问
同时会话对象。 容器必须确保操纵
表示会话属性的内部数据结构在线程中执行
安全的方式。 开发人员有责任确保线程安全地访问
属性对象本身。这将保护内部的属性集合
HttpSession 对象从并发访问,消除机会
应用程序导致该集合损坏。
因此,您唯一关心的是属性本身的威胁安全性。例如。如果它是ArrayList,并且您担心它的线程安全,您可能希望将其包装在Collections#synchronizedList() 中。
【解决方案2】:
它是一个同步过程。我刚刚做了一个示例程序。
JSP 代码:
<%
session.setAttribute("ID","12324");
session.setAttribute("ID2","656565");
%>
attributeAdded()方法的监听代码:
String attributeName = event.getName();
Object attributeValue = event.getValue();
System.out.println("Attribute added : " + attributeName + " : " + attributeValue);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("After Sleep : "+attributeName);
输出:
Attribute added : ID : 12324
After Sleep : ID
Attribute added : ID2 : 656565
After Sleep : ID2
所以你可以看到,只有在为第一个 id 打印“After Sleep”之后,它才会在会话中添加第二个 id