写点什么

浅谈 ConcurrentHashMap,2021 大厂 Android 面试题精选

用户头像
Android架构
关注
发布于: 1 小时前

ConcurrentHashMap?是线程安全且高效的 HashMap。


不同版本 jdk 实现它的方式存在些许不同,本篇文章主要基于 JDK1.8 进行分析。


1 为什么使用 ConcurrentHashMa


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码

p

  1. HashMap是线程不安全的。在多线程环境下,使用 HashMap 进行 put 操作会引起死循环。

  2. HashTable的效率低下,因为它几乎在所有方法上都使用 synchronized 来保证线程安全。

  3. ConcurrentHashMap在 put、remove 等修改数据操作时,只锁住某个“桶”的方式,有效提升并发访问率。

2 主要方法

2.1 put()

先上波源码再来分析。


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;}



第一步做了一个校验,key 或 value 为 null 都会抛出异常。 然后获取 hash 值,初始化 binCount 用于记录链表长度。



这里是个无限循环。

先判断 table 有没有初始化,没有就进行初始化。

(n - 1) & hash计算出插入下标,如果这个位置没有数据,直接放进去。

(fh = f.hash) == MOVED 如果其他线程在扩容,帮助其扩容。


// 有冲突后,进去 elsesynchronized (f) { // 锁住当前头节点 if (tabAt(tab, i) == f) { // 再次确认下标位置是否是 f 节点 if (fh >= 0) { // 头节点 hash 值 > 0 说明是链表 binCount = 1;for (Node<K,V> e = f;; ++binCount) { // 遍历 K ek;// 如果 key 相同,则判断是否覆盖旧值 if (e.hash == hash &&

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
浅谈ConcurrentHashMap,2021大厂Android面试题精选