概述
一、介绍
HashMap是非线程安全的,而Hashtable虽然是性能安全的,但是性能太低。
ConcurrentHashMap
是Java里面同时兼顾性能和线程安全的一个键值对集合。
HashTable
是一个线程安全的类,因为它的所有 public
方法都被 synchronized
修饰,这样就导致了一个问题,就是效率太低。
二、JDK1.7中是分段锁的思想
基于hash定位segment数组的索引
三、JDK1.8的实现
数据结构采用了和HashMap一样的数据结构,即数组 + 链表或数组 + 红黑树
但是安全方面, ConcurrentHashMap通过CAS去保障
四、ConcurrentHashMap在迭代时和HashMap的区别
当一个集合在迭代的时候如果动态的添加或者删除元素,那么就会抛出 Concurrentmodificationexception
,但是在 ConcurrentHashMap
里面却不会,例如如下代码:
public static void main(String[] args) {
Map<String,String> map = new ConcurrentHashMap<String, String>();
map.put("a","a1");
map.put("b","b1");
map.put("c","c1");
map.put("d","d1");
map.put("e","e1");
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()){
String it = iterator.next();
if("b".equals(it)){
map.remove("d");
}
System.out.println(it);
}
}
控制台打印如下:
a
b
c
e
而当你把 ConcurrentHashMap
换成 HashMap
的时候,控制台就会抛出一个异常:
Exception in thread "main" a
b
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
at java.util.HashMap$KeyIterator.next(HashMap.java:1466)
at xyz.somersames.ListTest.main(ListTest.java:22)
原因在于 ConcurrentHashMap
的 next
方法并不会去检查 modCount
和 expectedModCount
,但是会检查下一个节点是不是为空
if ((p = next) == null)
throw new NoSuchElementException();
当我们进行remove的时候, ConcurrentHashMap
会直接通过修改指针的方式来进行移除操作,同样的,也会锁住 数组
的头节点直至移除结束,所以在同一个时刻,只会有一个线程对 当前数组下标的所有节点
进行操作。
但是在 HashMap
里面, next
方法会进行一个check,而remove操作会修改 modCount
,导致 modCount
和 expectedModCount
不相等,所以就会导致ConcurrentModificationException
稍微修改下代码:
public static void main(String[] args) {
Map<String,String> map = new ConcurrentHashMap<String, String>();
map.put("a","a1");
map.put("b","b1");
map.put("c","c1");
map.put("d","d1");
map.put("e","e1");
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()){
if("b".equals(iterator.next())){
map.remove("d");
}
System.out.println(iterator.next());
}
}
控制台打印如下:
b
d
Exception in thread "main" java.util.NoSuchElementException
at java.util.concurrent.ConcurrentHashMap$KeyIterator.next(ConcurrentHashMap.java:3416)
at com.xzh.ssmtest.ListTest.main(ListTest.java:25)
并发下的处理
由于每一个 Node
的首节点都会被 synchronized
修饰,从而将一个元素的新增转化为一个原子操作,同时 Node
的 value
和 next
都是由 volatile
关键字进行修饰,从而可以保证可见性。
参考:
ConcurrentHashMap1.7分段锁原理
JDK1.8下ConcurrentHashMap的一些理解(一)
最后
以上就是优秀高山为你收集整理的总结:ConcurrentHashMap一、介绍二、JDK1.7中是分段锁的思想三、JDK1.8的实现四、ConcurrentHashMap在迭代时和HashMap的区别的全部内容,希望文章能够帮你解决总结:ConcurrentHashMap一、介绍二、JDK1.7中是分段锁的思想三、JDK1.8的实现四、ConcurrentHashMap在迭代时和HashMap的区别所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复