[问题] :使用ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>>
是否安全可靠。
[可选回答] :还有另外一个并发地图类型呢?那么并发集合呢?
P.S。 我只问java.util.concurrent
个包裹。
特定用法背景:
//we have
ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>> map = new ConcurrentHashMap<Object, ConcurrentHashMap<Object, Object>>();
//each string can be executed separately and concurently
ConcurrentHashMap<Object, Object> subMap = new ConcurrentHashMap<Object, Object>()
map.put(key, subMap);
map.remove(key);
map.get(key);
map.get(key).put(key, ref);
map.get(key).remove(key);
也许我的解决方案围绕着Guava HashBasedTable?
答案 0 :(得分:3)
如果没有您计划使用集合的特定上下文,则无法定义线程安全性。
您命名的并发集合本身就是线程安全的,因为它们的内部不变量不会被并发访问破坏;但这只是线程安全检查表中的一个要点。
如果您对结构执行的操作不仅仅是单个操作(整体上必须是原子操作),那么仅使用这些类就不会获得线程安全性。您将不得不求助于经典锁定,或者一些非常复杂,通常没有动力的无锁更新方案。
使用您问题中的示例,请考虑以下事项。
线程1执行
map.get(mapKey).put(key, value);
同时,线程2执行
map.remove(mapKey);
结果如何?线程1可能会将某些内容放入已删除的地图中,或者甚至可能会从null
获得get
结果。在大多数情况下,正确性需要更多的协调。
答案 1 :(得分:2)
Concurrent Collections意味着多个线程可以同时对集合执行添加/删除操作,不是它不是线程安全的
更多细节:
进一步请阅读
What's the difference between ConcurrentHashMap and Collections.synchronizedMap(Map)? Is ConcurrentHashMap totally safe?
答案 2 :(得分:1)
并发集合对于读取是线程安全的;但是,如果竞争并发更新或修改集合而另一个线程正在迭代它,您必须期望ConcurrentModificationException
。
答案 3 :(得分:1)
这是ConcurrentHashMap
的javadoc所说的:
但是,即使所有操作都是线程安全的,检索操作也不需要锁定,并且没有任何支持以阻止所有访问的方式锁定整个表
因此,它们在修改它时是线程安全的。
更新
同样的javadoc http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html说:
检索操作(包括get)一般不会阻塞,因此可能与更新操作重叠(包括put和remove)。检索反映了最近完成的更新操作的结果。对于诸如putAll和clear之类的聚合操作,并发检索可能反映仅插入或删除某些条目。类似地,Iterators和Enumerations在迭代器/枚举的创建时或之后的某个时刻返回反映哈希表状态的元素。 他们不会抛出ConcurrentModificationException 。但是,迭代器被设计为一次只能由一个线程使用。
答案 4 :(得分:1)
通常,作为java.util.concurrent一部分的类在额外编码复杂性的(潜在)惩罚下提供额外的性能。
我在嵌套ConcurrentMap实例时看到的问题是管理使用给定键的值填充外部地图。如果所有的键都是预先知道的,并且在某种初始化阶段将值放在地图中,则没有问题(但您也可能不需要将外部地图设置为ConcurrentMap)。如果您需要能够随时将新地图插入到外部地图中,则工作会变得复杂一些。在创建要插入外部地图的新地图时,您需要使用putIfAbsentmethod [1]并注意返回的值以确定要向其添加数据的实例。
[1] - http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent(K,%20V)