八股day1——HashMap
HashMap
回答重点
- 数组+链表+红黑树
- 超过负载因子会*2扩容,扩容操作比较耗时
- 尾插法,头插法在多线程中可能会形成回路,可以参考BV1n541177Ea
红黑树优化
-
当链表长度超过8时,链表会转变为红黑树,查找复杂度从O(n)降到
O(logn),如果树中元素低于6,则转换回链表,减少不表的树操作开销
hashCode()和equals()
- hashCode()用于计算hash值,equals()比较两个键是否相同
- equals()相等,对象一定相等,而hashCode()不能推出同样结论
ConcurrentHashMap
-
是 Java 中提供的一个线程安全的哈希表实现,它在多线程环境下提供了高效的并发访问。
-
实现思路:当塞入一个值的时候,先计算key的hash后的下标,如果计算到的下标还未有Node,就通过cas塞入新的Node。如果已经有node则通过synchronized将这个node上锁,这样别的线程就无法访问这个node及其之后的所有结点。若key相等替换value,否则新增一个node同HashMap。
-
结点维护:baseCount可以理解为总结点数,如果修改成功就直接返回,如果失败说明此时有线程在竞争,这时启动planB。既每个线程单独维护自己的数量CounterCell,结果为baseCount+所有CounterCell。好处为减少并发场景对单个成员变量的竞争压力,提高了并发度,也就是LongAdder思想。
cas操作
-
原子操作,compare and swap,它比较内存中的某个值是否为预期值,如果是则更新为新值,否则不做修改。
-
失败重试:如果不等,说明其他线程修改了该值,cas操作失败,一般会利用重试,直到成功。
优点:
- 无锁并发,比用锁的性能更高
- 原子性,性能安全
缺点:
- 单变量限制
- ABA问题:如果一个变量值从A->B->A,cas无法检测到这种变化,可能导致错误(可解决:如引入时间戳检测到变量的变化)
-
Atomic类中封装了CAS操作
为什么jdk1.8对HashMap进行了红黑树的改动
-
1.8之前,用链表来解决hash冲突。当hash冲突较多时,链表中的元素增多,查找,插入和删除的时间复杂度从O(1)退化为O(n)。而红黑树的时间复杂度为O(logn)。
-
除了链表长度影响树化,实际上还与数组长度有关。某个桶中元素数量>=8,且数组长度大于等于64,则树化。
-
为什么树化有数组条件限制?因为树化有开销。
-
为什么不能舍弃链表就用红黑树?因为红黑树结点大小是链表结点大小的两倍。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端