我目前正在使用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。
所以我的问题是,
- 如何在多线程环境中创建测试,使
Multimaps.newSetMultimap(new ConcurrentHashMap<>(), ConcurrentHashMap::newKeySet)
无法正常工作?或者它只是意外地与ConcurrentHashMap
一起工作 - 如果这行代码不适用于多线程环境,有人能建议我一种在多线程处理中提高多映射READ性能的方法吗
非常感谢。
您可以使用:
ConcurrentMap<K, CopyOnWriteArraySet<V>> multimap = new ConcurrentHashMap<>();
您可以实现:
class ConcurrentArraySetMultimap<K, V> implements SetMultimap<K, V> {
如果Javadoc声明Multimaps.newSetMultimap()
不是线程安全的,我不会试图证明它是错误的。我查看了实现,原因可能是在经过修饰的Map
和Set
之上运行了额外的逻辑。
然而,我创建了一个用于并发读写的测试代码,它似乎可以工作(没有任何异常,如ConcurrentModificationException(">
您无法真正测试线程安全性。线程安全漏洞并不总是发生——它们只是偶尔发生,而且当它们发生时会非常令人困惑
正如Xaerxess在评论中所链接的那样,没有真正的方法可以同时支持整个Multimap
接口并获得良好的性能。解决方案不是使用Multimap接口,而是拥有自己的ConcurrentMap<K, Set<V>>
,并且要非常小心。(在Java 7中,这将相当困难,因为ConcurrentMap
接口更受限制,没有原子更新操作。(