[英]High-performance Concurrent MultiMap Java/Scala
我正在寻找高性能、并发的 MultiMap。 我到处搜索,但我根本找不到使用与 ConcurrentHashMap 相同方法的解决方案(仅锁定哈希数组的一部分)。
多图将经常被读取、添加和删除。
multimap 键将是一个字符串,它的值将是任意的。
我需要 O(1) 来查找给定键的所有值,O(N) 可以删除,但 O(logN) 将是首选。
删除给定键的最后一个值会从键中删除值的容器,以免泄漏内存,这一点至关重要。
编辑:这是我构建的解决方案,在 ApacheV2 下可用: 索引(多图)
为什么不用一些漂亮的 Scala 式方法(例如隐式转换为 Iterable 或任何您需要的方法,以及更新方法)来包装 ConcurrentHashMap[T,ConcurrentLinkedQueue[U]] ?
你试过谷歌收藏吗? 他们有各种Multimap实现。
我做了一个ConcurrentMultiMap mixin,它扩展了 mutable.MultiMap mixin 并有一个 concurrent.Map[A, Set[B]] 自我类型。 它按键锁定,具有 O(n) 空间复杂度,但如果您不是特别需要大量写入,它的时间复杂度非常好。
我有一个要求,我必须有一个Map<Comparable, Set<Comparable>>
,其中在 Map 上的插入是并发的,也在相应的 Set 上,但是一旦从 Map 中消耗了一个 Key,就必须将其删除,想想如果作为每两秒运行一次的作业,它消耗来自特定键的整个Set<Comparable>
但插入是完全并发的,以便在作业启动时缓冲大多数值,这是我的实现:
注意:我使用 Guava 的辅助类 Maps 来创建并发映射,而且,这个解决方案模拟了实践清单 5.19 中的 Java 并发:
import com.google.common.collect.MapMaker;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
/**
* A general purpose Multimap implementation for delayed processing and concurrent insertion/deletes.
*
* @param <K> A comparable Key
* @param <V> A comparable Value
*/
public class ConcurrentMultiMap<K extends Comparable, V extends Comparable>
{
private final int size;
private final ConcurrentMap<K, Set<V>> cache;
private final ConcurrentMap<K, Object> locks;
public ConcurrentMultiMap()
{
this(32, 2);
}
public ConcurrentMultiMap(final int concurrencyLevel)
{
this(concurrencyLevel, 2);
}
public ConcurrentMultiMap(final int concurrencyLevel, final int factor)
{
size=concurrencyLevel * factor;
cache=new MapMaker().concurrencyLevel(concurrencyLevel).initialCapacity(concurrencyLevel).makeMap();
locks=new MapMaker().concurrencyLevel(concurrencyLevel).initialCapacity(concurrencyLevel).weakKeys().weakValues().makeMap();
}
private Object getLock(final K key){
final Object object=new Object();
Object lock=locks.putIfAbsent(key, object);
if(lock == null){
lock=object;
}
return lock;
}
public void put(final K key, final V value)
{
synchronized(getLock(key)){
Set<V> set=cache.get(key);
if(set == null){
set=Sets.newHashSetWithExpectedSize(size);
cache.put(key, set);
}
set.add(value);
}
}
public void putAll(final K key, final Collection<V> values)
{
synchronized(getLock(key)){
Set<V> set=cache.get(key);
if(set == null){
set=Sets.newHashSetWithExpectedSize(size);
cache.put(key, set);
}
set.addAll(values);
}
}
public Set<V> remove(final K key)
{
synchronized(getLock(key)){
return cache.remove(key);
}
}
public Set<K> getKeySet()
{
return cache.keySet();
}
public int size()
{
return cache.size();
}
}
我在这个话题上有点晚了,但我认为,现在,你可以像这样使用番石榴:
Multimaps.newSetMultimap(new ConcurrentHashMap<>(), ConcurrentHashMap::newKeySet)
使用 Gauava 的 MultiMaps。 Multimaps.synchronizedMultimap(HashMultimap.create())
讨论已经晚了,但......
当涉及到高性能并发的东西时,应该准备好编写解决方案。 与 Concurrent 中的魔鬼在细节中的陈述具有完整的含义。 可以实现完全并发和无锁的结构。
起始基础将是 NonBlocking Hashtable http://sourceforge.net/projects/high-scale-lib/ ,然后取决于每个键有多少个值以及需要在写入 Object[] 时为值添加/删除一些副本的频率或带有信号量/自旋锁的基于数组的集合。
您是否看过用于实时等的Javalution ,当然还有高性能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.