多线程环境中的快速MultiMap



我目前正在使用Guava Multimap实现。

map = Multimaps.synchronizedSetMultimap(HashMultimap.<K, R> create());

然而,我发现我的程序性能现在受到Multimaps.synchronizedSetMultimap中使用的同步块synchronized (mutex)的限制。

因此,我正在寻找是否有任何同步多映射的替代方案,希望它能帮助提高多线程环境中的程序性能。

我不介意是否施加额外的限制,比如只有一个线程用于更新(创建、修改或删除(,只要我可以使用多个线程读取多映射数据,同时允许写入操作。此外,对于我的项目使用,我主要读取数据(如果时间允许,则为>99%(,很少写入数据(<1%(,因此与读取性能相比,我不太关心写入性能(。


从高性能并发多映射Java/Scala,有人建议使用

Multimaps.newSetMultimap(new ConcurrentHashMap<>(), ConcurrentHashMap::newKeySet)

由于我使用的是Java7,我将上面的代码转换如下:

map = Multimaps.newSetMultimap(new ConcurrentHashMap<K, Collection<R>>(), new Supplier<Set<R>>() {
public Set<R> get() {
return Sets.newSetFromMap(new ConcurrentHashMap<R, Boolean>());
}
});

这似乎真的很有效。但从文件来看,它指出了以下内容:

当任何并发操作更新多映射时,即使映射和工厂生成的实例是线程安全的,多映射也是不安全的。并发读取操作将正常工作。要允许并发更新操作,请使用对synchronizedSetMultimap(com.google.common.collect.SetMultimap<K,V>(的调用包装多映射。

然而,我已经创建了一个用于并发读写的测试代码,它似乎可以工作(没有任何异常,如ConcurrentModificationException(。我目前的Java版本是Java 7,使用的是Guava 14.0.1。

所以我的问题是,

  1. 如何在多线程环境中创建测试,使Multimaps.newSetMultimap(new ConcurrentHashMap<>(), ConcurrentHashMap::newKeySet)无法正常工作?或者它只是意外地与ConcurrentHashMap一起工作
  2. 如果这行代码不适用于多线程环境,有人能建议我一种在多线程处理中提高多映射READ性能的方法吗

非常感谢。

您可以使用:

ConcurrentMap<K, CopyOnWriteArraySet<V>> multimap = new ConcurrentHashMap<>();

您可以实现:

class ConcurrentArraySetMultimap<K, V> implements SetMultimap<K, V> {


如果Javadoc声明Multimaps.newSetMultimap()不是线程安全的,我不会试图证明它是错误的。我查看了实现,原因可能是在经过修饰的MapSet之上运行了额外的逻辑。

然而,我创建了一个用于并发读写的测试代码,它似乎可以工作(没有任何异常,如ConcurrentModificationException(">

无法真正测试线程安全性。线程安全漏洞并不总是发生——它们只是偶尔发生,而且当它们发生时会非常令人困惑

正如Xaerxess在评论中所链接的那样,没有真正的方法可以同时支持整个Multimap接口并获得良好的性能。解决方案不是使用Multimap接口,而是拥有自己的ConcurrentMap<K, Set<V>>,并且要非常小心。(在Java 7中,这将相当困难,因为ConcurrentMap接口更受限制,没有原子更新操作。(

最新更新