我正在寻找一个高性能,并发的MultiMap。我到处搜索但是我找不到使用与ConcurrentHashMap相同的方法的解决方案(仅锁定哈希数组的一部分)。
多重地图将经常被阅读,添加和删除。
multimap键将是一个String,它的值将是任意的。
我需要O(1)来查找给定键的所有值,O(N)可以删除,但O(logN)将是首选。
至关重要的是,删除给定键的最后一个值将从键中删除值的容器,以免泄漏内存。
这是我建立的解决方案,在ApacheV2下可用: Index (multimap)
答案 0 :(得分:12)
为什么不将ConcurrentHashMap [T,ConcurrentLinkedQueue [U]]与一些类似Scala的方法一起包装(例如隐式转换为Iterable或者你需要什么,以及更新方法)?
答案 1 :(得分:8)
您是否尝试过Google收藏?他们有各种Multimap实现。
答案 2 :(得分:4)
虽然我没有使用它,但仍有one in akka。
答案 3 :(得分:3)
我制作了一个ConcurrentMultiMap mixin,它扩展了mutable.MultiMap mixin,并且有一个concurrent.Map [A,Set [B]]自我类型。它锁定每个键,具有O(n)空间复杂度,但如果你不是特别重写,它的时间复杂度非常好。
答案 4 :(得分:1)
答案 5 :(得分:1)
我有一个要求,我必须有一个Map<Comparable, Set<Comparable>>
,其中Map上的插入是并发的,也是相应的Set,但是一旦从Map中消耗了一个Key,就必须将其删除,如果作为一个每两秒运行一次的Job,它从一个特定的Key中消耗整个Set<Comparable>
,但是插入完全是并发的,以便在Job启动时缓冲大多数值,这是我的实现:
注意:我使用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();
}
}
答案 6 :(得分:1)
使用来自Gauava的MultiMap。
Multimaps.synchronizedMultimap(HashMultimap.create())
答案 7 :(得分:0)
你有没看过Javalution用于实时等等,当然还有高性能。
答案 8 :(得分:0)
讨论迟到了,但是......
当谈到高性能并发资源时,应该准备好对解决方案进行编码。 使用Concurrent声明魔鬼在细节中具有完整的含义。 可以完全并发和无锁地实现结构。
起始基数将是NonBlocking Hashtable http://sourceforge.net/projects/high-scale-lib/,然后取决于每个键的值多少以及需要在写入Object []上添加/删除某些副本的值或基于数组的Set with semaphore / spin lock
答案 9 :(得分:0)
我对这个话题有点迟,但我想,现在,你可以像这样使用番石榴:
Multimaps.newSetMultimap(new ConcurrentHashMap<>(), ConcurrentHashMap::newKeySet)