本文共 5888 字,大约阅读时间需要 19 分钟。
Java ConcurrentHashMap class is part of the Concurrency Collection Classes. It’s a hash table implementation, which supports concurrent retrieval and updates. It’s used in a multi-threaded environment to avoid .
Java ConcurrentHashMap类是并发集合类的一部分。 这是一个哈希表实现,支持并发检索和更新。 在多线程环境中使用它可以避免 。
If we try to modify the collection while iterating over it, we get ConcurrentModificationException
. Java 1.5 introduced Concurrent classes in the java.util.concurrent
package to overcome this scenario. ConcurrentHashMap is the Map implementation that allows us to modify the Map while iteration. The ConcurrentHashMap operations are thread-safe. ConcurrentHashMap doesn’t allow null for keys and values.
如果我们尝试在迭代集合时修改集合,则会得到ConcurrentModificationException
。 Java 1.5在java.util.concurrent
包中引入了Concurrent类来克服这种情况。 ConcurrentHashMap是Map实现,它允许我们在迭代时修改Map。 ConcurrentHashMap操作是线程安全的。 ConcurrentHashMap不允许键和值为null。
The ConcurrentHashMap
class is similar to , except that it’s thread-safe and allows modification while iteration.
ConcurrentHashMap
类与相似,但它是线程安全的,并允许在迭代时进行修改。
package com.journaldev.util;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapExample { public static void main(String[] args) { //ConcurrentHashMap MapmyMap = new ConcurrentHashMap (); myMap.put("1", "1"); myMap.put("2", "1"); myMap.put("3", "1"); myMap.put("4", "1"); myMap.put("5", "1"); myMap.put("6", "1"); System.out.println("ConcurrentHashMap before iterator: "+myMap); Iterator it = myMap.keySet().iterator(); while(it.hasNext()){ String key = it.next(); if(key.equals("3")) myMap.put(key+"new", "new3"); } System.out.println("ConcurrentHashMap after iterator: "+myMap); //HashMap myMap = new HashMap (); myMap.put("1", "1"); myMap.put("2", "1"); myMap.put("3", "1"); myMap.put("4", "1"); myMap.put("5", "1"); myMap.put("6", "1"); System.out.println("HashMap before iterator: "+myMap); Iterator it1 = myMap.keySet().iterator(); while(it1.hasNext()){ String key = it1.next(); if(key.equals("3")) myMap.put(key+"new", "new3"); } System.out.println("HashMap after iterator: "+myMap); }}
Output:
输出 :
ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793) at java.util.HashMap$KeyIterator.next(HashMap.java:828) at com.test.ConcurrentHashMapExample.main(ConcurrentHashMapExample.java:44)
It’s clear from the output that ConcurrentHashMap takes care of the new entry in the map while iteration whereas HashMap throws ConcurrentModificationException
.
从输出中可以清楚地看到, ConcurrentHashMap在迭代时会处理映射中的新条目,而HashMap则抛出ConcurrentModificationException
。
Let’s look at the exception stack trace closely. The following statement has thrown Exception.
让我们仔细看看异常堆栈跟踪。 以下语句引发了Exception。
String key = it1.next();
It means that the new entry got inserted in the HashMap but Iterator is failing. Actually, Iterator on Collection objects is fail-fast i.e any modification in the structure or the number of entries in the collection object will trigger the exception.
这意味着新条目已插入HashMap中,但Iterator失败。 实际上,对Collection对象的Iterator是快速失败的,即,对结构的任何修改或collection对象中条目的数量都会触发异常。
We have taken the set of keys from HashMap and then iterating over it.
我们从HashMap中获取了一组键,然后对其进行迭代。
HashMap contains a variable to count the number of modifications and iterator use it when you call its next() function to get the next entry.
HashMap包含一个变量,用于计算修改次数,并且迭代器在调用其next()函数以获取下一个条目时使用它。
HashMap.java
:
HashMap.java
:
/** * The number of times this HashMap has been structurally modified * Structural modifications are those that change the number of mappings in * the HashMap or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the HashMap fail-fast. (See ConcurrentModificationException). */ transient volatile int modCount;
Let’s change the code a little bit to come out of the iterator loop when we insert the new entry. All we need to do is add a break statement after the put call.
当我们插入新条目时,让我们稍微更改一下代码使其从迭代器循环中出来。 我们需要做的就是在put调用之后添加一个break语句。
if(key.equals("3")){ myMap.put(key+"new", "new3"); break;}
The output with the above code:
上面的代码输出:
ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}HashMap after iterator: {3=1, 2=1, 1=1, 3new=new3, 6=1, 5=1, 4=1}
What if we don’t add a new entry but update the existing key-value pair?
如果我们不添加新条目而是更新现有的键值对怎么办?
Will it throw exception?
会抛出异常吗?
Let’s change the code in the original program and check it out.
让我们在原始程序中更改代码并签出。
//myMap.put(key+"new", "new3");myMap.put(key, "new3");
There won’t be any exception because the collection is modified but its structure remains the same.
不会有任何例外,因为集合已被修改,但其结构保持不变。
Did you notice those angle brackets while creating our collection object and Iterator?
在创建我们的集合对象和迭代器时,您是否注意到那些尖括号?
It’s called generics and it’s very powerful when it comes to type-checking at compile time to remove ClassCastException at runtime. Learn more about generics in .
它被称为泛型,当在编译时进行类型检查以在运行时删除ClassCastException时,它非常强大。 在了解有关泛型的更多信息。
You should also read and .
您还应该阅读和 。
Reference:
参考:
翻译自:
转载地址:http://aaozd.baihongyu.com/