在另一个内部的一个并发集合:它是线程安全的

时间:2014-02-26 13:22:45

标签: java collections map concurrency

[问题] :使用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?

5 个答案:

答案 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)