注意:JDK1.7与JDK1.8中的ConcurrentHashMap主要延续HashMap的设计与思想,是在其基础上进行的相应优化

1.JDK1.7中的底层实现原理

(1)JDK1.7ConcurrentHashMap的底层结构,延续HashMap的底层设计,采用数组+链表

(2)不同的是:ConcurrentHashMap中的数组被分为大数组和小数组,大数组是Segment,小数组是HashEntry

Segment本身是基于ReentrantLock可重入锁来实现加锁和释放锁,这样就能保证多线程同时访问ConcurrentHashMap的时候,同一时间只能有一个线程操作对应的节点,以此来保证线程安全

总结:这里基于Segment加锁和释放锁,因此称之为分段锁或分片锁

2.JDK1.8中的底层实现原理

(1)JDK1.8的ConcurrentHashMap底层采用的是数组+链表+红黑树,这里对JDK1.7进行了优化,在链表长度大于8并且数组长度大于64时链表就会转化为红黑树

(2)JDK1.8中保留了Segment的定义,这仅仅是为了保证序列化时的兼容性,不再有任何结构上的用途

(3)JDK1.8中主要使用volatile+CAS或者是synchronized的方法来实现的,以此来保证线程安全

(i)源码中,添加元素时,首先会判断容器是否为空,为空,就会使用volatile加CAS来初始化

(ii)容器不为空,就会根据存储的元素计算该位置是否为空,如果计算结果位置的结果为空,就会使用CAS来设计该节点,不为空,就会使用synchronized来加锁实现,然后遍历桶中的数据并且替换或者新增节点到桶中,最后判断是否需要转换红黑树

总结:JDK1.8中ConcurrentHashMap是通过对头节点加锁来保证线程安全,降低锁粒度,发生hash冲突和加锁的频率也更低了



附上JDK1.8源码

 /**
* Maps the specified key to the specified value in this table.
* Neither the key nor the value can be null.
*
* <p>The value can be retrieved by calling the {@code get} method
* with a key that is equal to the original key.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}
* @throws NullPointerException if the specified key or value is null
*/
public V put(K key, V value) {
return putVal(key, value, false);
} /** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}

最新文章

  1. 安卓真机调试 出现Installation error: INSTALL_FAILED_UPDATE_INCOMPATIBLE....
  2. 解决OracleConnection ORA-1017 和 HRESULT:0x8007000B 错误
  3. java开发环境
  4. Node.js高效按行输出文件内容
  5. JSP公用COMMON文件
  6. 日期运算 jsf日期组建
  7. windows 8 设置hyper-v网络设置
  8. LeetCode Find Minimum in Rotated Sorted Array II
  9. [python]倒计时实现
  10. BZOJ 1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果
  11. 一些提高开发效率的 Category
  12. 数据可视化开源系统(python开发)
  13. perl学习(8) 控制:unless,until,next,redo,last
  14. [转]Blue Prism Architecture
  15. python,列表,元祖,字典
  16. Jmeter 登入、新增、查询、修改、删除,动态传参。
  17. 版本控制git第一篇
  18. 用Axios Element 实现全局的请求 loading
  19. 【jsp】配置错误页面
  20. discuz formhash

热门文章

  1. JavaScript使用原型链实现继承
  2. Mybatis框架基础入门(四)--SqlMapConfig.xml配置文件简介
  3. 2020/12/28为止好用的PC下载工具
  4. Redis 最适合的场景?
  5. Java 中,Maven 和 ANT 有什么区别?
  6. @Controller 注解?
  7. 学习FastDfs(一)
  8. Kube-OVN:大型银行技术团队推荐的金融级云原生网络方案
  9. 数据库SQL之学习SUM总和套用条件CASE WHEN语句
  10. 攻防世界php_rce