说到ConcurrentHashMap,首先就要聊聊HashMap了
HashMap的底层是数组+链表结合在一起使用。
HashMap的底层数据结构为数组+链表+红黑树实现
当链表的长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索的时间。
将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树。
JDK5中添加了新的concurrent包,在线程安全的基础上提供了更好的写并发能力,但同时降低了对读一致性的要求。
ConcurrentHashMap是java.util.concurrent下的类;
在并发编程中,ConcurrentHashMap是一个经常被使用的数据结构,它的实际与实现非常精巧,大量利用volatile,final,CAS等技术来减少锁竞争对于性能的影响。
简单的对比
ContcurrentHashMap基于JDK1.8的源码剖析
public V put(K key, V value) {
//实际调用的是putVal(key,value,false)
//无论key在表中所对应的值是否存在,都使用value进行更新
return putVal(key, value, false);
}
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
//key和value的值必须是非null的
if (key == null || value == null) throw new NullPointerException();
//计算key的hash值用来定位元素的位置
int hash = spread(key.hashCode());
int binCount = 0;
//table 引用指向的是ConcurrentHashMap中 所有元素所存在的数组的引用 所以下面依次将遍历
for (ConcurrentHashMap.Node<K,V>[] tab = table;;) {
ConcurrentHashMap.Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();//table为空,则初始化table,首次初始化默认的数组长度为16
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
// 判断key对应的数组位置上是否为null,若尚未发生hash碰撞,即进行CAS操作,new 一个 Node<K,V>存放到tab中,退出for循环;
if (casTabAt(tab, i, null,
new ConcurrentHashMap.Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
//判断是否需要扩容
else if ((fh = f.hash) == MOVED) // MOVED = -1
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) {//加锁
if (tabAt(tab, i) == f) {
if (fh >= 0) {//当作链表处理
binCount = 1;
for (ConcurrentHashMap.Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {// key 存在,更新
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
ConcurrentHashMap.Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new ConcurrentHashMap.Node<K,V>(hash, key,
value, null);//key 不存在,链表中追加新元素
break;
}
}
}
//按照红黑树的方式进行插入
else if (f instanceof ConcurrentHashMap.TreeBin) {
ConcurrentHashMap.Node<K,V> p;
binCount = 2;
//key不存在则putTreeVal方法直接添加新元素并返回null,key存在则返回对应节点p并做val更新
if ((p = ((ConcurrentHashMap.TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
//当插入链表后值大于8的时候要转为红黑树
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
//size++
addCount(1L, binCount);
return null;
}
put方法流程图
4月11日20:30~22:00通过腾讯会议进行了第二次在线学习讨论我把学习笔记整理一下...
DELETEFROMTablesWHEREIDNOTIN(SELECTMin(ID)FROMTablesGROUPBYName) Min的话保...
正则忽略大小写 – RegexOptions.IgnoreCase 例如: 复制代码 代码如下: Str = R...
错误描述: 在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报...
项目中用到的一些特殊字符和图标 html代码 XML/HTML Code 复制内容到剪贴板 div ...
工具:Eclipse,Oracle,smartupload.jar;语言:jsp,Java;数据存储:Oracle。...
复制代码 代码如下: % URL="http://news.163.com/special/00011K6L/rss_newstop....
Elasticsearch 是通过 Lucene 的倒排索引技术实现比关系型数据库更快的过滤。特...
本文实例讲述了Laravel框架源码解析之反射的使用。分享给大家供大家参考,具体如...
上篇文章给大家介绍了 Java正则表达式匹配,替换,查找,切割的方法 ,接下来,...