如果我有一个始终更新的ConcurrentHashMap(添加更多或参加条目......有时可能为空)...
在恒定时间内是否有任何有效的方法,我可以从中随机获取一个值?
答案 0 :(得分:0)
你可以分两步完成:
1 - 随时将值克隆到数组
2 - 通过生成随机索引
从数组中获取随机值Random generator = new Random();
Object[] values = concurrentHashMap.values().toArray();
Object randomValue = values[generator.nextInt(values.length)];
答案 1 :(得分:0)
地图的大小是否会发生变化?如果它没有,那么我能想到的最佳方法就是:
map.values().get(random);
您也可以使用密钥集执行此操作:
map.get(map.keyset().get(random));
请注意,读者线程不会阻止编写器线程,但编写者在极少数情况下会阻止读取器。这意味着不幸的写入(或垃圾收集)会阻止读取操作并减慢执行速度。
如果您愿意接受稍微不那么随机的方法,您可能会创建一种算法,避免从发生写入的区域进行读取,以防止因锁定而造成速度损失。
调用ConcurrentHashMap的构造函数时,请确保指定并发级别作为默认值,优化16个写入器的内部分片,这可能太多了。
答案 2 :(得分:0)
似乎没有一种方法可以获得密钥或条目的随机访问视图,而无需在其中的某个位置制作O(n)副本。副本可能会非常快;不要优化,直到你知道这是一个问题。
我能想到的唯一选择是保持与地图并行的条目列表。每次添加到地图时,也会添加到列表中。任何时候你从一个删除,从另一个删除。您可以将它包装在您自己的Map
实现中:
public class RandomAccessConcurrentHashMap<K,V> implements Map<K,V> {
private List<K> backingList = new ArrayList();
private Map<K,V> backingMap = new ConcurrentHashMap<>();
public V put(K key, V value) {
backingList.add(value);
return backingMap.put(key,value);
}
...
}
(原则上 - 您需要考虑线程安全性,并且可能找到比ArrayList
更高效的存储空间