在什么情况下它将不是线程安全的

时间:2013-05-04 11:43:55

标签: java servlets thread-safety

全部,为了更好地理解Attributes线程问题的HttpSession。我为它编写了一些测试代码,我原以为下面的代码应该是线程安全的方法。

HttpSession session = request.getSession();
synchronized (session) {
  Integer n = (Integer) session.getAttribute("foo");
  session.setAttribute("foo", (n == null) ? 1 : n + 1);
}  

但实际上它的Answer告诉我它不是。我只是无法理解它,在我看来,我认为会话是一个客户端和服务器之间的转换。这种情况是否存在任何线程问题?如果有,请告诉我在哪种情况下此代码不是线程安全的。感谢。

1 个答案:

答案 0 :(得分:1)

AFAIK,没有什么能阻止servlet容器每次线程请求会话时返回不同的对象(即实际会话中的代理)。

如果容器这样做,在会话上同步将没有任何帮助,因为每个线程将在不同的对象上同步。

拥有线程安全计数器的最简单方法是使用AtomicInteger,并调用其增量方法之一,但这并不会阻止两个并发线程第一次存储AtomicInteger,如果它们都将其视为空。

确保最简单的方法(尽管可能不是最快)是使用全局锁来获取属性:

public static synchronized AtomicInteger getCounterFromSession(HttpSession session) {
    AtomicInteger counter = (AtomicInteger) session.getAttribute("counter");
    if (counter == null) {
        counter = new AtomicInteger();
        session.setAttribute("counter", counter);
    }
    return counter;
}

也就是说,在群集应用程序中,会话在群集的节点之间进行持久化或复制,因此也不会带来任何保证。将计数器存储在数据库中将是解决方案。