ServletContext对象的线程安全性

时间:2013-11-25 10:41:37

标签: java java-ee servlets

我在我的ServletContext中存储了一个HashMap对象。 但是多个请求线程正在读取和修改此HashMap。

因为我相信ServletContext对象是在请求线程之间共享的,我是否需要同步对此HashMap的访问?或者还有其他更好的方法可以达到目的吗?

5 个答案:

答案 0 :(得分:14)

通过ServletContext#setAttribute发布属性是线程安全的!这可以从Java Servlet规范,第4.5章得出:(...)任何属性绑定 进入上下文可用于属于同一Web的任何其他servlet 应用程序。(...)

(原因:使对象可用于其他servlet也意味着可以将其提供给其他线程。这是唯一可行的,如果使用了正确的同步,则ServletContext#setAttribute}必须同步。

因此,通过ServletContext#getAttribute阅读已发布的属性也是如此。

但是当然如果在不同的线程之间共享像HashMap之类的对象,开发人员必须确保以适当的线程安全方式访问此共享对象本身!使用问题的其他答案中已经说明的ConcurrentHashMap是一种可能的解决方案,但是在初始化属性时没有解决竞争条件,因为null检查不是原子的:

ConcurrentMap<String, Object> shared = (...)servletContext.getAttribute("sharedData");
if (shared == null) {
    shared = new ConcurrentHashMap<>();
    servletContext.setAttribute("sharedData", shared);
}

因此,可以使用ServletContextListener在Web应用程序启动时初始化上下文!

答案 1 :(得分:3)

@Artem Moskalev建议,您可以使用ConcurrentHashMap并使用putIfAbsent方法来存储对象/值,而不是简单的put方法。

我想在@Artem Moskalev'的答案下面添加此评论,但我没有足够的声誉。

答案 2 :(得分:1)

多线程环境中的最佳方法是使用 java.util.concurrent.ConcurrentHashMap 。 它的设计特别允许您在没有任何ConcurrentModificationException的情况下阅读和修改它。然而,在迭代的情况下,您应该在其实例上进行同步,以便始终获得可预测的结果。

如果以多线程方式从那里检索其他任何内容,则在上下文中进行同步会给您带来很多开销。所以ConcurrentHashMap是一个更好的解决方案。

你可以在这里阅读:

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html

  

支持检索的完全并发和可调整的哈希表   预期的更新并发性。检索操作(包括获取)   一般不阻塞,因此可能与更新操作重叠   (包括放置和删除)。

答案 3 :(得分:0)

是的,请确保在修改HashMap时;它是同步的或线程安全的。

答案 4 :(得分:-1)

您需要同步ServletContext对象。例如: -

synchronized(ctx){
 //your code here
}