我想基于API文档澄清一下ConcurrentHashMap与ConcurrentSkipListMap的内容。
从我的理解ConcurrentHashMap gaurantees线程安全插入多个线程。因此,如果您的地图只能由多个线程同时填充,那么就没有问题。然而,API继续建议它不会锁定检索,所以你可能会在这里得到误导性的结果?
相反,对于ConcurrentSkipListMap,它表示:“插入,删除,更新和访问操作由多个线程安全地并行执行”。所以我假设这没有哈希映射所具有的上述检索问题,但显然这通常会带来性能成本?
在实践中,是否有人发现需要使用ConcurrentSkipListMap,因为这种特殊行为,或者检索通常不会导致过期视图?
答案 0 :(得分:4)
检索反映了最近完成的更新的结果 开始时的行动。对于诸如的集合操作 putAll和clear,并发检索可能反映插入或 只删除一些条目。
它使用get(key)
的volatile语义。如果Thread1调用put(key1, value1)
并且在Thread2调用get(key1)
之后,Thread2将不会等待Thread1完成其put
,它们彼此不同步并且Thread2 可以获得旧的关联值。但是,如果在Thread2尝试put(key1, value1)
之前在Thread1中完成get(key1)
,则保证Thread2获得此更新(value1
)。
ConcurrentSkipListMap已排序并提供
containsKey,get的平均log(n)时间成本 放置和删除操作及其变体
ConcurrentSkipListMap
不是那么快,但在您需要排序的线程安全地图时非常有用。
答案 1 :(得分:2)
然而,API继续表明它没有保护锁定以便检索,因此您可能会在此处获得误导性结果?
有趣的是,ConcurrentSkipListMap也没有,事实上CSLM完全没有阻塞。
在Java 7中,出于所有意图和目的,CHM在执行读取时是非阻塞的。实际上,Java 8更新的CHM实现具有完全无阻塞的读取。
这里的要点是CHM和CSLM具有相似的读取语义,不同之处在于时间复杂度。
答案 2 :(得分:0)
从您的问题来看,您似乎已经得出结论,只有ConcurrentHashMap
的插入才是线程安全的。
从我的理解ConcurrentHashMap gaurantees线程安全插入多个线程。因此,如果您的地图只能由多个线程同时填充,那么就没有问题。
你是怎么得出这个结论的? ConcurrentHashMap
文档的第一行暗示所有操作都是线程安全的:
一个哈希表,支持检索的完全并发和可更新的预期并发性。
此外,它意味着get()
操作可以维持比put()
操作更高的并发性。
简单地说ConcurrentHashMap
没有您认为具有的检索问题。在大多数情况下,您应该使用ConcurrentHashMap
而不是ConcurrentSkipListMap
,因为ConcurrentHashMap
的效果通常优于ConcurrentSkipListMap
。当您需要具有可预测迭代顺序的CurrentSkipListMap
或者您需要ConcurrentMap
的工具时,您应该只使用NavigableMap
。