Domanda

I have a Android Application whose core component is a HashMap<String,float[]>. The System is having high concurrency. e.g here are the following three situations I have which occur frequently and they are highly overlapping in nature

  1. Iterate through all the keys in the hashmap and do some operation on its value(read only operations).
  2. Add new key,value pairs in the Hashmap.
  3. Remove Certain keys from the Hashmap.

I do all these operations in different threads and thus am using a ConcurrentHashMap since some inconsistency in retrievals doesnt matter. e.g While iterating the map,if new entries are added then it doesnt matter to not read in those new values immediately as I ensure that next time they are read .

Also while removing the entries I am recreating the iterator everytime to avoid "ConcurrentModificationException"

Suppose , there is a following hashmap(i.e ConcurrentHashmap)

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

Now for Retrieval I do the following

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)
            }

and for removal I do the following

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

and when inserting in new values I simply do

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

I am not sure if its a very efficient utilisation. Also it does matter not to read in removed values(however I need efficiency ,and since the iterator is again created during the function call,its guaranteed that in the next time I don't get the removed values)so that much inconsistency can be tolerated?

Could someone please tell me an efficient way to do it?

PS. I forgot to mention that why I am doing the removal operation in such a way. I have now changes the condition on which its deleted from equal to contains(there might be multiple stings having the prefix "abc" followed by different suffixes. so I need to delete all those then.

È stato utile?

Soluzione

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

Don't iterate over the key set to then retrieve the values too - iterate over the entry set directly:

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

This is more efficient in general (even for "normal" HashMaps), but it will also reduce contention in your case (half as many accesses to the map).

Add new key,value pairs in the Hashmap.

Yes it is simply: map.put(s, f);

Remove Certain keys from the Hashmap.

If you need to check that the key contains a given substring then you do need to iterate over the keys like you are doing, although I'm not sure why you have a while+for+break instead of a simple for.

Altri suggerimenti

Because of the way you are using the ConcurrentHashMap, you are precisely removing its Concurrent characteristics. Your attempts at (re-)synchronization will work very frequently, but not always.

Have you considered to leave the keys in the HashMap? I'm thinking of something like:

    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);
        }
    }

If keys are too volatile (i.e. after a while you would have too many DELETED items), then you can create a cleanup Thread.

According to ConcurrentHashMap API its iterators never throw ConcurrentModificationException so you dont need to break after removal. But in any case the correct way to iterate and remove is this

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

this way it will work even with fail-fast iterators without ConcurrentModificationException

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top