有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何高效地使用ConcurrentHashMap?

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

  1. 迭代hashmap中的所有键并对其执行一些操作 它的值(只读操作)
  2. 在Hashmap中添加新的键、值对
  3. 从Hashmap中删除某些键

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

此外,在删除条目时,我每次都会重新创建迭代器,以避免“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.我忘了提到我为什么要以这种方式进行移除操作。 我现在已经更改了将其从等于包含的位置删除的条件(可能有多个Sting,前缀为“abc”,后跟不同的后缀。因此,我需要删除所有这些Sting。


共 (3) 个答案

  1. # 1 楼答案

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

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

    这样,即使在没有ConcurrentModificationException的情况下,它也可以使用快速失败的迭代器

  2. # 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);
            }
        }
    

    如果键太不稳定(即,过一段时间后,您将有太多的已删除项),则可以创建清理Thread

  3. # 3 楼答案

    Iterate through all the keys in the hashmap and do some operation on its value(read only operations).

    不要迭代密钥集,然后也检索值-直接迭代条目集:

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

    这通常效率更高(即使对于“普通”哈希映射也是如此),但在您的情况下,它也会减少争用(对映射的访问次数减少一半)

    Add new key,value pairs in the Hashmap.

    是的,它只是:map.put(s, f);

    Remove Certain keys from the Hashmap.

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