有没有有效的方法从dinamically更新的Java ConcurrentHashMap获取随机值?

时间:2017-05-24 07:05:38

标签: java

如果我有一个始终更新的ConcurrentHashMap(添加更多或参加条目......有时可能为空)...

在恒定时间内是否有任何有效的方法,我可以从中随机获取一个值?

3 个答案:

答案 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更高效的存储空间