高性能并发MultiMap Java / Scala

时间:2010-09-03 11:31:55

标签: java scala concurrency multimap

我正在寻找一个高性能,并发的MultiMap。我到处搜索但是我找不到使用与ConcurrentHashMap相同的方法的解决方案(仅锁定哈希数组的一部分)。

多重地图将经常被阅读,添加和删除。

multimap键将是一个String,它的值将是任意的。

我需要O(1)来查找给定键的所有值,O(N)可以删除,但O(logN)将是首选。

至关重要的是,删除给定键的最后一个值将从键中删除值的容器,以免泄漏内存。

这是我建立的解决方案,在ApacheV2下可用: Index (multimap)

10 个答案:

答案 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)

你应该试试ctries。这是pdf

答案 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)