我正在编写一个Web服务,它严重依赖于每小时完全更新一次的单个大型Map。剩下的时间里,许多线程同时读取该表。
我的问题是:实现这样一个地图最有效的结构是什么?
地图可以更大(100 - 500 MB)。除了每小时更换一次整个地图之外,只有读取权限。
我正在考虑使用Java HashMap,并且可能使用反射在更新之间设置字段final,如果这可以提高性能,但我不知道如何使JVM优化多个并发读取。
答案 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();
}
}