Java 有效地使用 ConcurrentHashMap?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18555506/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using ConcurrentHashMap efficiently?
提问by Debarshi Dutta
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
我有一个 Android 应用程序,其核心组件HashMap<String,float[]>.
是具有高并发性的系统。例如,这是我经常发生的以下三种情况,它们在性质上高度重叠
- Iterate through all the keys in the hashmap and do some operation on its value(read only operations).
- Add new key,value pairs in the Hashmap.
- Remove Certain keys from the Hashmap.
- 遍历哈希图中的所有键并对其值进行一些操作(只读操作)。
- 在 Hashmap 中添加新的键值对。
- 从 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 .
我在不同的线程中执行所有这些操作,因此使用 ConcurrentHashMap,因为检索中的某些不一致并不重要。例如,在迭代地图时,如果添加了新条目,那么不立即读取这些新值并不重要,因为我确保下次读取它们时。
Also while removing the entries I am recreating the iterator everytime to avoid "ConcurrentModificationException"
此外,在删除条目时,我每次都重新创建迭代器以避免“ConcurrentModificationException”
Suppose , there is a following hashmap(i.e ConcurrentHashmap)
假设,有如下hashmap(即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.
附注。我忘了说为什么我要以这种方式进行删除操作。我现在改变了从等于到包含删除的条件(可能有多个带有前缀“abc”后跟不同后缀的字符串。所以我需要删除所有这些。
采纳答案by assylias
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).
这通常更有效(即使对于“普通”HashMaps),但它也会减少您的情况(对地图的访问次数减半)。
Add new key,value pairs in the Hashmap.
在 Hashmap 中添加新的键值对。
Yes it is simply: map.put(s, f);
是的,它很简单: map.put(s, f);
Remove Certain keys from the Hashmap.
从 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.
如果您需要检查键是否包含给定的子字符串,那么您确实需要像您正在做的那样迭代键,尽管我不确定为什么您有一个 while+for+break 而不是一个简单的 for。
回答by Mario Rossi
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.
由于您使用 的方式ConcurrentHashMap
,您正在精确地删除其Concurrent
特征。您对(重新)同步的尝试将非常频繁,但并非总是如此。
Have you considered to leave the keys
in the HashMap
? I'm thinking of something like:
你有没有考虑过要离开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);
}
}
If keys are too volatile (i.e. after a while you would have too many DELETED items), then you can create a cleanup Thread
.
如果键太不稳定(即一段时间后您将有太多 DELETED 项目),那么您可以创建一个 cleanup Thread
。
回答by Evgeniy Dorofeev
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
根据 ConcurrentHashMap API,它的迭代器永远不会抛出 ConcurrentModificationException,因此您不需要在删除后中断。但无论如何,迭代和删除的正确方法是这样的
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
这样它甚至可以在没有 ConcurrentModificationException 的情况下使用快速失败的迭代器