[问题]:使用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?
如果没有计划在其中使用集合的特定上下文,就无法定义线程安全性。
您命名的并发集合本身是线程安全的,因为它们的内部不变量不会被并发访问破坏;然而,这只是线程安全检查表上的一个要点。
如果您对结构执行的操作不止一个,而结构作为一个整体必须是原子操作,那么仅通过使用这些类将无法获得线程安全性。你将不得不求助于经典的锁定,或者一些非常复杂的、通常没有动机的、无锁定的更新方案。
使用问题中的示例,考虑以下内容。
线程1执行
map.get(mapKey).put(key, value);
同时,线程2执行
map.remove(mapKey);
结果如何?线程1可能正在将某个东西放入已经删除的映射中,或者它甚至可能从get
获得null
结果。在大多数情况下,需要更多的协调才能确保正确性。
并发集合意味着多个线程可以同时对集合执行添加/删除操作,否,这不是线程安全的
更多详细信息:
欲了解更多信息,请阅读
什么';ConcurrentHashMap和Collections.synchronizedMap(Map)之间的区别是什么?ConcurrentHashMap完全安全吗?
并发集合对读取是线程安全的;但是,在竞争并发更新的情况下,或者在另一个线程对集合进行迭代时修改集合时,您必须期望ConcurrentModificationException
这就是ConcurrentHashMap
的javadoc所说的:
然而,即使所有操作都是线程安全的,检索操作也不需要锁定,并且不支持以阻止所有访问的方式锁定整个表
因此,他们在修改它方面是线程安全的。
更新
相同的javadochttp://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html说:
检索操作(包括get)通常不阻塞,因此可能与更新操作(包括put和remove)重叠。重试反映了最近完成的更新操作在开始时保持的结果。对于putAll和clear等聚合操作,并发检索可能只反映插入或删除某些条目。类似地,迭代器和枚举返回的元素反映了在创建迭代器/枚举时或之后某个时刻的哈希表状态它们不抛出ConcurrentModificationException。然而,迭代器被设计为一次只能由一个线程使用。
通常,作为java.util.concurrent的一部分的类提供了额外的性能,但(潜在的)代价是额外的编码复杂性。
我在嵌套ConcurrentMap实例中看到的问题是管理在给定键处使用值填充外部映射。如果所有的键都是预先已知的,并且在某种初始化阶段将值放置在映射中,那么就没有问题(但您也可能不需要外部映射是ConcurrentMap)。如果你需要能够在进行时将新地图插入外部地图,那么这项工作就会变得有点复杂。当创建一个新的映射插入外部映射时,您需要使用putIfAbsent方法[1]并注意返回的值,以确定向哪个实例添加数据。
[1] -http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent(K,%20V)