并发只读HashMap

时间:2014-02-06 23:21:52

标签: java hashmap concurrenthashmap

我正在编写一个Web服务,它严重依赖于每小时完全更新一次的单个大型Map。剩下的时间里,许多线程同时读取该表。

我的问题是:实现这样一个地图最有效的结构是什么?

地图可以更大(100 - 500 MB)。除了每小时更换一次整个地图之外,只有读取权限。

我正在考虑使用Java HashMap,并且可能使用反射在更新之间设置字段final,如果这可以提高性能,但我不知道如何使JVM优化多个并发读取。

4 个答案:

答案 0 :(得分:15)

由于地图在使用时未更新,因此请使用HashMap,这样可以提供出色的O(1)查找性能(牺牲线程安全性)。

什么时候刷新,建立一个新地图并交换参考。

考虑使用AtomicReference使交换线程安全:

private final AtomicReference<Map<K, V>> mapRef = new AtomicReference<>();

使用:

mapRef.get().get(key);

初始化或交换新地图:

Map<K, V> newMap = new HashMap<>();
// populate map
mapRef.set(newMap); // all threads will see this change

答案 1 :(得分:2)

在你的场景中,在你证明Java的标准HashMap不够快之前,我认为你可能需要担心垃圾收集,如果在这里停止这个世界并且可能会出现问题。

您可以通过始终重复使用HashMap(每次都不创建新的HashMap)并预先分配存储在地图中的所有对象并重复使用它来避免此问题。

除此之外,你可以使用两个HashMaps来更快地进行替换,正如@Bohemian在他的回答中建议的那样。

答案 2 :(得分:1)

转到ConcurrentHashMap。它允许并发读取访问,而不会影响性能。

答案 3 :(得分:-1)

使用此功能。

public class Model {
  private Map<?, ?> values;
  private ReadWriteLock lock = new ReentrantReadWriteLock();

  public ? getValue(? key) {
    lock.readLock().lock();
    ? rv = values.get(key);
    lock.readLock().unlock();
    return rv;
  }

  public void update(Map<?, ?> values) {
    lock.writeLock().lock();
    rv = values;
    //OR rv.putAll(values)
    lock.writeLock().unlock();
  }
}