JDK1.8 之前 HashMap 底层是 数组和链表, 之后在之前基础上加上红黑树。

相比于之前的版本, JDK1.8 之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。

HashMap 在容量不够进行 resize 时由于高并发可能出现死链,导致 CPU 飙升,为了避免这种情况的发生,建议在高并发场景下,可以使用其他数据结构来替代 HashMap,比如 ConcurrentHashMap,它是一种线程安全的哈希表实现,在高并发情况下能够保证并发性能和数据一致性。另外,还可以通过加锁的方式来避免死链的发生,比如使用 ReentrantLock 等锁机制,来保证对 HashMap 的操作是线程安全的。

HashMap 在高并发场景下可能出现的性能问题以及如何规避这些问题

首先,HashMap 是一种常用的哈希表实现,它用于存储 key-value 键值对,并提供了快速的插入、删除和查找操作。在 HashMap 中,元素的存储位置是根据 key 的哈希值来计算的,相同哈希值的元素会被放置在同一个桶(bucket)中。当 HashMap 中的元素个数达到了负载因子(load factor)所设置的阈值时,就需要对 HashMap 进行扩容操作,从而保证 HashMap 的性能。

但是,在进行扩容操作时,由于需要重新计算元素的哈希值,重新放置元素的位置,以及调整桶的大小等操作,可能会导致多个线程同时对同一个桶进行操作,从而发生死链(链表死循环)的情况。当发生死链时,CPU 的使用率会急剧飙升,严重影响系统的性能。

为了避免这种情况的发生,建议在高并发场景下,可以使用其他数据结构来替代 HashMap,比如 ConcurrentHashMap,它是一种线程安全的哈希表实现,在高并发情况下能够保证并发性能和数据一致性。另外,还可以通过加锁的方式来避免死链的发生,比如使用 ReentrantLock 等锁机制,来保证对 HashMap 的操作是线程安全的。

综上所述,为了避免 HashMap 在高并发情况下出现死链的情况,我们可以选择使用其他数据结构,或者采取加锁等措施来保证对 HashMap 的操作是线程安全的,从而避免CPU飙升的情况。

死链问题

死链问题通常是指在HashMap中的链表或树形结构中的某个元素失去了对其他元素的正确引用,导致链表或树的结构破裂。这通常在高并发场景下出现,因为多个线程同时对HashMap进行操作时可能会导致数据结构不一致。让我们通过一个简单的例子来说明死链问题。

假设我们有一个HashMap,其初始容量为16,哈希函数为hash(key) % 16。假设现在有两个线程A和B,它们同时对HashMap执行以下操作:

在线程A和线程B并发操作时,假设以下操作顺序发生:

线程A插入(key1, value1),将其放入bucket 1。

线程A开始插入(key2, value2),检查bucket 1并发现已存在一个元素,因此需要将(key2, value2)放在bucket 1的链表头部。此时,线程A已经获取了链表头部的引用。

在线程A完成插入操作之前,线程B开始插入(key3, value3)。线程B检查bucket 1并发现已存在一个元素,因此需要将(key3, value3)放在bucket 1的链表头部。线程B完成了插入操作。

线程A继续完成插入(key2, value2),但此时链表的结构已被线程B修改。由于线程A之前已经获取了链表头部的引用,它会将(key2, value2)插入到原始链表头部的下一个位置。这样,链表中的元素顺序将变为:(key3, value3) -> (key2, value2) -> (key1, value1)。

在这个例子中,虽然(key2, value2)没有丢失,但由于线程A和线程B的并发操作,链表的最终顺序可能与预期不符。在某些情况下,这可能会导致性能下降,例如在查找元素时需要遍历更长的链表。要避免这种问题,可以使用线程安全的数据结构,如ConcurrentHashMap。

https://javaguide.cn/java/collection/java-collection-questions-02.html#hashmap-多线程操作导致死循环问题看这个

HashMap 在高并发场景下可能出现的性能问题以及如何规避这些问题的更多相关文章

  1. Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%。再往后,每提高0.1%,优化难度成指数级增长了。哪怕是千分之一,也直接影响用户体验,影响每天上万张机票的销售额。 在高并发场景下,提供了保证线程安全的对象、方法。比如经典的ConcurrentHashMap,它比起HashMap,有更小粒度的锁,并发读写性能更好。线程安全的StringBuilder取代S

    Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%.再往后,每提高0.1%,优化难度成指数级增长了.哪怕是千分之一,也直接影响用户体验,影响每天上万张机 ...

  2. 高并发场景下System.currentTimeMillis()的性能问题的优化 以及SnowFlakeIdWorker高性能ID生成器

    package xxx; import java.sql.Timestamp; import java.util.concurrent.*; import java.util.concurrent.a ...

  3. 高并发场景下System.currentTimeMillis()的性能问题的优化

    高并发场景下System.currentTimeMillis()的性能问题的优化 package cn.ucaner.alpaca.common.util.key; import java.sql.T ...

  4. HttpClient在高并发场景下的优化实战

    在项目中使用HttpClient可能是很普遍,尤其在当下微服务大火形势下,如果服务之间是http调用就少不了跟http客户端找交道.由于项目用户规模不同以及应用场景不同,很多时候可能不需要特别处理也. ...

  5. C++高并发场景下读多写少的解决方案

    C++高并发场景下读多写少的解决方案 概述 一谈到高并发的解决方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也 ...

  6. C++高并发场景下读多写少的优化方案

    概述 一谈到高并发的优化方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也能很大的影响整体性能,本文从单模块下读 ...

  7. Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载

    Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...

  8. 【转】记录PHP、MySQL在高并发场景下产生的一次事故

    看了一篇网友日志,感觉工作中值得借鉴,原文如下: 事故描述 在一次项目中,上线了一新功能之后,陆陆续续的有客服向我们反应,有用户的个别道具数量高达42亿,但是当时一直没有到证据表示这是,确实存在,并且 ...

  9. 高并发场景下System.currentTimeMillis()的性能优化

    一.前言 System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我也不知道,不过听说在100倍左右),然而该方法又是一个常用方法, 有时不得不使用, ...

  10. MySQL在大数据、高并发场景下的SQL语句优化和"最佳实践"

    本文主要针对中小型应用或网站,重点探讨日常程序开发中SQL语句的优化问题,所谓“大数据”.“高并发”仅针对中小型应用而言,专业的数据库运维大神请无视.以下实践为个人在实际开发工作中,针对相对“大数据” ...

随机推荐

  1. 在jooq的POJO类中使用Lombok的Data注解

    jooq生成pojo类的配置根据官方给的如下: https://www.jooq.org/doc/3.14/manual/getting-started/tutorials/jooq-in-7-ste ...

  2. Solution -「NOI Simu.」树

    \(\mathscr{Description}\)   给定 \(n\), 集合 \(\{a_m\}\), 称一棵无标号但儿子有序的有根树合法, 当且仅当叶子权值存在一个因数在 \(\{a_m\}\) ...

  3. CDS标准视图:催款范围 I_DunningArea

    视图名称:催款范围 I_DunningArea 视图类型:基础 视图代码: 点击查看代码 @AccessControl.authorizationCheck: #CHECK //authority c ...

  4. CF div2 996(A~D)

    手速场,前三题偏简单,后三题偏难.赛时三题,C题做法麻烦了些导致过得不是很快,但最后打得也不是很差. A 两只青蛙相邻时,可移动的青蛙一定输:直接把该青蛙挤到边缘即可. 而是否相邻可以直接用二者初始间 ...

  5. react 计算衍生数据

    import React from 'react' import { connect } from 'react-redux' import TodoList from '../components/ ...

  6. Collection接口方法

     Collection 接口继承树 Collection 接口Collection 接口是 List.Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 ...

  7. arthas进行java应用不停服务情况下的class文件热部署更新

    我们在工作的过程中会遇到java应用已经部署或升级投入使用,发现某个单元文件有bug需要修正,但是客户的应用目前不能停止,而且不能因为一个非致命的bug来进行整个平台的一次升级.我们需要进行单文件的更 ...

  8. 0425-字符输入流FileReader

    package A10_IOStream; import java.awt.datatransfer.StringSelection; import java.io.IOException; impo ...

  9. uni-app如何只用插件市场中的插件

    将你需要的插件下载下来.比如说如下图 在pages.json配置 globalStyle是一个单独的字段 "globalStyle": { "usingComponent ...

  10. react之state两种不同的写法

    我发现 state 有两种不同的写法 在构造器 constructor 中是这样的 有 this. constructor(props){//参数必须要有 super(props); this.sta ...