Java 中的 ConcurrentHashMap

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 QuestionsJava.中的迭代器设计模式

您可以从我们的giHub Repository.]签出更多JAVA集合示例

参考:Doc接口

Published At
Categories with 技术
Tagged with
comments powered by Disqus