2

我有一个 Android 应用程序,其核心组件是HashMap<String,float[]>. 系统具有高并发性。例如,这是我经常发生的以下三种情况,它们本质上是高度重叠的

  1. 遍历哈希图中的所有键并对其值进行一些操作(只读操作)。
  2. 在 Hashmap 中添加新的键值对。
  3. 从哈希图中删除某些键。

我在不同的线程中执行所有这些操作,因此使用 ConcurrentHashMap ,因为检索中的一些不一致并不重要。例如,在迭代地图时,如果添加了新条目,那么不立即读取这些新值并不重要,因为我确保下次读取它们。

此外,在删除条目时,我每次都重新创建迭代器以避免“ConcurrentModificationException”

假设,有以下hashmap(即ConcurrentHashmap)

ConcurrentHashMap<String,float[]> test=new ConcurrentHashMap<String, float[]>(200);

现在进行检索,我执行以下操作

Iterator<String> reader=test.keySet().iterator();
            while(reader.hasNext())
            {
                String s=reader.next();
                float[] temp=test.get(s);
                //do some operation with float[] temp here(read only operation)
            }

对于删除,我执行以下操作

boolean temp = true;
        while (temp) {
            for (String key : test.keySet()) {
                temp = false;
                if (key.contains("abc")) {
                    test.remove(key);
                    temp = true;
                    break;
                }
            }
        }

当插入新值时,我只是这样做

test.put("temp value", new float[10]);

我不确定它是否是一种非常有效的利用方式。另外,不要读入已删除的值也很重要(但是我需要效率,并且由于在函数调用期间再次创建了迭代器,因此可以保证下次我不会得到已删除的值),因此可能会出现很多不一致容忍?

有人可以告诉我一个有效的方法吗?

PS。我忘了提为什么我要以这种方式进行删除操作。我现在已经改变了它从等于包含删除的条件(可能有多个带有前缀“abc”的字符串,后跟不同的后缀。所以我需要删除所有这些。

4

3 回答 3

4

遍历哈希图中的所有键并对其值进行一些操作(只读操作)。

不要遍历键集然后也检索值 - 直接遍历条目集:

for (Map.Entry<String, float[]> e : map.entrySet() {
    String key = e.getKey();
    float[] value = e.getValue();
    //do something with them
}

这通常更有效(即使对于“正常” HashMaps),但它也会减少您的情况下的争用(对地图的访问次数减半)。

在 Hashmap 中添加新的键值对。

是的,它很简单:map.put(s, f);

从哈希图中删除某些键。

如果您需要检查键是否包含给定的子字符串,那么您确实需要像您正在做的那样迭代键,尽管我不确定为什么您有一个 while+for+break 而不是一个简单的 for。

于 2013-09-01T06:08:26.643 回答
2

由于您使用 的方式ConcurrentHashMap,您正在精确地删除它的Concurrent特征。您对(重新)同步的尝试将非常频繁地工作,但并非总是如此。

你有没有考虑过keys离开HashMap?我在想类似的东西:

    public static final float[] DELETED= new float[0] ;

    /* delete */
    test.put(key,DELETED);

    /* insert */
    test.put(key,value);

    /* iterate */
    for(Map.Entry<String,float[]> e: test.entrySet ) {
        if( e.getValue() != DELETED ) {
            operateOn(e);
        }
    }

如果键太不稳定(即一段时间后您将有太多已删除的项目),那么您可以创建一个 cleanup Thread

于 2013-09-01T05:45:41.203 回答
0

根据 ConcurrentHashMap API,它的迭代器永远不会抛出 ConcurrentModificationException 所以你不需要在删除后中断。但无论如何,迭代和删除的正确方法是这样

for (Iterator<String> i = test.keySet().iterator(); i.hasNext();) {
     String next = i.next();
     if (next.equals("abc")) {
             i.remove();
     }
}

这样,即使使用没有 ConcurrentModificationException 的快速失败迭代器,它也可以工作

于 2013-09-01T05:46:30.967 回答