Java ConcurentHashMap类是并发集合类的一部分。它是一个哈希表实现,支持并发检索和更新。它在多线程环境中使用,以避免ConcurrentModificationException.
并发HashMap
如果我们试图在迭代集合的同时修改它,我们会得到ConCurrentModificationException
。Java 1.5在java.util.concurent
包中引入了并发类来克服这种情况。ConcurrentHashMap是允许我们修改Map While迭代的Map实现。ConcurrentHashMap操作是线程安全的。ConcurrentHashMap不允许键和值为空。
Java ConCurentHashMap示例
ConCurrentHashMap
类类似于HashMap,不同之处在于它是线程安全的,允许在迭代时修改。
1package com.journaldev.util;
2
3import java.util.HashMap;
4import java.util.Iterator;
5import java.util.Map;
6import java.util.concurrent.ConcurrentHashMap;
7
8public class ConcurrentHashMapExample {
9
10 public static void main(String[] args) {
11
12 //ConcurrentHashMap
13 Map<String,String> myMap = new ConcurrentHashMap<String,String>();
14 myMap.put("1", "1");
15 myMap.put("2", "1");
16 myMap.put("3", "1");
17 myMap.put("4", "1");
18 myMap.put("5", "1");
19 myMap.put("6", "1");
20 System.out.println("ConcurrentHashMap before iterator: "+myMap);
21 Iterator<String> it = myMap.keySet().iterator();
22
23 while(it.hasNext()){
24 String key = it.next();
25 if(key.equals("3")) myMap.put(key+"new", "new3");
26 }
27 System.out.println("ConcurrentHashMap after iterator: "+myMap);
28
29 //HashMap
30 myMap = new HashMap<String,String>();
31 myMap.put("1", "1");
32 myMap.put("2", "1");
33 myMap.put("3", "1");
34 myMap.put("4", "1");
35 myMap.put("5", "1");
36 myMap.put("6", "1");
37 System.out.println("HashMap before iterator: "+myMap);
38 Iterator<String> it1 = myMap.keySet().iterator();
39
40 while(it1.hasNext()){
41 String key = it1.next();
42 if(key.equals("3")) myMap.put(key+"new", "new3");
43 }
44 System.out.println("HashMap after iterator: "+myMap);
45 }
46
47}
输出 :
1ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
2ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}
3HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
4Exception in thread "main" java.util.ConcurrentModificationException
5 at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
6 at java.util.HashMap$KeyIterator.next(HashMap.java:828)
7 at com.test.ConcurrentHashMapExample.main(ConcurrentHashMapExample.java:44)
从输出中可以清楚地看到,ConcurentHashMap 负责在迭代时处理map中的新条目,而HashMap抛出ConcurentModifiationException
。让我们仔细看看异常堆栈跟踪。以下语句引发异常。
1String key = it1.next();
这意味着新条目已插入到HashMap中,但Iterator失败。实际上,Collection对象上的迭代器是Fail-fast ,即集合对象中的任何结构或条目数量的任何修改都会触发异常。
迭代器如何获知Collection中的修改?
我们从HashMap中获取了一组密钥,然后对其进行迭代。HashMap包含一个变量来计算修改次数,迭代器在您调用它的Next()函数以获取下一个条目时使用它。HashMap.java
:
1/**
2 * The number of times this HashMap has been structurally modified
3 * Structural modifications are those that change the number of mappings in
4 * the HashMap or otherwise modify its internal structure (e.g.,
5 * rehash). This field is used to make iterators on Collection-views of
6 * the HashMap fail-fast. (See ConcurrentModificationException).
7 */
8 transient volatile int modCount;
让我们稍微更改一下代码,以便在插入新条目时退出迭代器循环。我们所需要做的就是在PUT调用之后添加一条Break语句。
1if(key.equals("3")){
2 myMap.put(key+"new", "new3");
3 break;
4}
具有上述代码的输出:
1ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
2ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}
3HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
4HashMap after iterator: {3=1, 2=1, 1=1, 3new=new3, 6=1, 5=1, 4=1}
修改密钥值会怎样?
如果我们不添加新的条目,而是更新现有的键值对怎么办?会抛出异常吗? 让我们更改原始程序中的代码并将其签出。
1//myMap.put(key+"new", "new3");
2myMap.put(key, "new3");
不会有任何异常,因为集合被修改,但其结构保持不变。
进一步阅读
在创建集合对象和迭代器时,您注意到那些尖括号了吗?它被称为泛型,当在编译时进行类型检查以在运行时删除ClassCastException时,它非常强大。了解有关泛型的更多信息,请参阅Java Generics Example.您还应该阅读Java Collection Interview Questions和Java.中的迭代器设计模式
您可以从我们的giHub Repository.]签出更多JAVA集合示例
参考:Doc接口