线程读取HashMap时另一线程触发扩容:get操作的可能结果
并发场景下HashMap的get操作与扩容put操作共存时的可能结果
当一个线程执行会触发扩容的put操作,另一个线程同时执行get操作时,由于HashMap本身非线程安全,get操作可能出现以下几种结果:
- 返回正确值:这是偶然情况。如果get操作的目标节点在扩容开始前就已被访问,或者扩容过程中该节点的转移动作未被get线程干扰,就能正常拿到对应的值,但这种结果完全不可靠,不能依赖。
- 返回null:扩容时原数组的节点会逐步转移到新数组。如果get线程刚好访问原数组中某个已被转移走的节点位置,会误以为该键不存在,从而返回null。
- 触发CPU飙升的死循环:在JDK 7及更早版本中,扩容会对链表进行反转,并发场景下可能导致链表形成环形结构。get线程遍历这个环形链表时会陷入无限循环,直接让CPU占用率拉满。JDK 8虽改用尾插法优化了扩容逻辑,但极端情况下仍有小概率出现类似问题。
- 返回错误值(旧值或其他键的值):扩容过程中节点的哈希计算、位置转移若被并发干扰,get线程可能访问到未完成更新的节点,拿到该键的旧值;或是误访问到其他键的节点,返回不属于当前查询键的值。
内容的提问来源于stack exchange,提问作者Manas Saxena
相关产品推荐
相关产品推荐

