2013-11-25 52 views
5

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

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

+0

你试过了TreeMap吗? – Prateek

+0

你可以把你的代码? –

回答

10

通过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

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

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

你可以阅读一下:

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

的哈希表支持更新检索的完全并发和可调 预期的并发性。检索操作(包括get) 一般不会阻塞,因此可能与更新操作 (包括put和remove)重叠。

-1

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

synchronized(ctx){ 
//your code here 
} 
+0

作为一般规则,您不应该使用您不控制的对象的内部(监视器)锁定。 – kbolino

2

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

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

+0

有一些代表。您可以立即添加评论。 :) –

0

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