【问题标题】:Concurrent read-only HashMap并发只读HashMap
【发布时间】:2014-02-06 23:21:51
【问题描述】:

我正在编写一个严重依赖于每小时完全更新一次的大型地图的网络服务。其余时间多个线程同时读取该表。

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

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

我在考虑只使用 Java HashMap,如果这样可以提高性能,也许可以使用反射在更新之间设置字段 final,但我不知道如何使 JVM 针对许多并发读取进行优化。

【问题讨论】:

  • 可以通过ReadWriteLock从外部管理访问。除此之外,您是否打算使其比“普通” HashMap 更高效?
  • 你有证据证明普通的HashMap不够用吗?
  • 我最怕的是每个线程都有自己的副本。我还读到 ConcurrentHashMap 只有并发写入的优点。

标签: java hashmap concurrenthashmap


【解决方案1】:

由于地图在使用时不会更新,因此请使用 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

【讨论】:

  • 谢谢这也是我考虑的!但是您能解释一下使用“AtomicReference”是什么意思吗?
【解决方案2】:

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

【解决方案3】:

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

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

除此之外,您可以通过使用@Bohemian 在他的回答中建议的两个 HashMap 来加快替换速度。

【讨论】:

    【解决方案4】:

    使用这个。

    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();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-11-03
      • 2015-11-26
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      • 1970-01-01
      • 2019-06-17
      • 2013-03-12
      相关资源
      最近更新 更多