2016-01-22 99 views
2

我想澄清一些关于ConcurrentHashMap vs ConcurrentSkipListMap的API文档。ConcurrentHashMap vs ConcurrentSkipListMap澄清

从我的理解ConcurrentHashMap gaurantees线程安全的多线程插入。所以如果你有一个只能被多个线程并发填充的地图,那么就没有问题了。然而,API继续建议它不保证检索的锁定,所以你可能会在这里得到误导结果?

相比之下,ConcurrentSkipListMap声明:“插入,删除,更新和访问操作安全地由多个线程同时执行”。所以我认为这没有前面提到的哈希映射的检索问题,但显然这通常会带来性能成本?

实际上,有没有人发现需要使用ConcurrentSkipListMap是因为这种特殊的行为,或者一般来说没有关系,检索可能会提供过时的视图?

回答

2

ConcurrentHashMap

反演反映最近完成的更新 操作拿着在他们发病的结果。对于汇总操作(如 )putAll和clear,并发检索可能反映插入或仅删除一些条目。

它使用易失性语义get(key)。当Thread1呼叫put(key1, value1)并紧接着Thread2呼叫get(key1)时,Thread2不会等待Thread1完成它的put,它们不会彼此同步,并且Thread2 可以获得旧的关联值。但是,如果put(key1, value1)在Thread1尝试到get(key1)之前在Thread1中完成,那么Thread2将保证获得此更新(value1)。

ConcurrentSkipListMap进行排序,并提供

预期平均log(n)的时间成本,为containsKey方法,获取 put和remove操作及其变体

ConcurrentSkipListMap没有那么快,但在需要排序的线程安全映射时非常有用。

+0

如果您想要获取最新的副本,那么您通常会如何处理这个问题 - 有没有办法使用不同的数据结构,或者使用ConcurrentHashMap来处理阻塞? – Tranquility

+0

实际上,在所有情况下'ConcurrentHashMap'就够了。对我来说,更新意味着能够看到完整的更新 - 而且它在'ConcurrentHashMap'中是如此。但是如果你想在put开始时立即阻止所有的地图获取,那么你有一些额外的同步。您可以使用效率低下的Collections.synchronizedMap()或者具有相应关联的ReadWriteLocks的严格大小的HashMap数组(像ConcurrentHashMap中的段)。请注意,这种阻塞几乎总是不必要的,并会影响性能。真诚的我无法想象什么时候你需要它。 – dezhik

1

但是,API继续暗示它不保证检索的锁定,因此您可能会在这里获得误导性结果?

有趣的是,ConcurrentSkipListMap,事实上CSLM也是完全非阻塞的。

在Java 7中对于所有意图和目的,CHM在执行读取时是非阻塞的。实际上,Java 8的更新的CHM实现具有完全无阻塞的读取。

这里的要点是CHM和CSLM具有相似的读取语义,区别在于时间复杂度。

+0

那么为什么API会这样说:“插入,删除,更新和访问操作安全地由多个线程同时执行。” ...? – Tranquility

+0

因为不会出现更新操作的竞争条件,所以他们使用'ReentrantLock'来进行相互同步。并且根据推测,所有完成的更新应该对获取可见 - 它的工作原理正如在读取时所说的那样。 – dezhik

+1

@Tranquility只是因为算法不是阻塞并不意味着它是线程不安全的。有像'ConcurrentLinkedQueue'这样的完全线程安全的非阻塞并发算法。 CHM使用阻塞和非阻塞读取/写入的组合来确保线程安全。 –

0

从你的问题,你似乎得出结论,只有插入到ConcurrentHashMap线程安全。

从我的理解ConcurrentHashMap gaurantees线程安全插入由多个线程。所以如果你有一个只能被多个线程并发填充的地图,那么就没有问题了。

你是如何得出这个结论的? ConcurrentHashMap的文档的第一行意味着所有操作都是线程安全的:

支持完全并发检索和可调整预期并发更新的哈希表。

此外,这意味着get()操作可以维持比put()操作更高级别的并发性。

简单地说,ConcurrentHashMap没有您认为它具有的检索问题。在大多数情况下,您应该使用ConcurrentHashMap而不是ConcurrentSkipListMap,因为ConcurrentHashMap的性能通常优于ConcurrentSkipListMap。当您需要具有可预测的迭代顺序的ConcurrentMap或者需要NavigableMap的设施时,您应该只使用CurrentSkipListMap