有效使用ConcurrentHashMap?

时间:2013-09-01 05:19:46

标签: java android concurrency concurrenthashmap

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

  1. 遍历hashmap中的所有键并执行一些操作 它的价值(只读操作)。
  2. 在Hashmap中添加新的键值对。
  3. 从Hashmap中删除某些键。
  4. 我在不同的线程中执行所有这些操作,因此使用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”后跟不同的后缀。所以我需要删除所有那些。

3 个答案:

答案 0 :(得分: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);

  

从Hashmap中删除某些键。

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

答案 1 :(得分: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);
        }
    }

如果键太易变(即一段时间后你会有太多DELETED项),那么你可以创建一个清理Thread

答案 2 :(得分:0)

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

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

这样,即使没有ConcurrentModificationException的失败快速迭代器,它也能正常工作