
深入剖析HashMap与ConcurrentHashMap内部原理及实现
3.13MB |
更新于2025-03-20
| 162 浏览量 | 举报
收藏
一、HashMap关键属性与方法
在Java中,HashMap是一个基于哈希表的Map接口实现,它存储的内容是键值对,并且允许使用null作为键和值。HashMap的内部通过一个数组和链表(Java 8中引入红黑树优化链表过长的情况)来处理键的冲突。
关键属性包括:
1. int threshold; // 下一次扩容的阈值
2. final float loadFactor; // 负载因子,默认值是0.75
put()方法实现:
1. 初始化或扩容检查:如果哈希表的数组为空或长度为0,则调用resize()方法初始化数组。resize()方法在首次插入时创建一个默认容量(16)的数组。
2. 计算桶位置并插入新节点:通过(n - 1) & hash计算键的桶索引(等价于取模运算,但更高效)。如果该位置为空,则直接插入新节点。
3. 处理哈希冲突:
- 首节点匹配:检查桶的第一个节点是否与待插入的key相同(哈希值和equals均匹配)。
- 红黑树插入:如果节点是TreeNode类型,则调用红黑树的插入方法putTreeVal。
- 链表遍历:遍历链表查找是否存在相同的key。如果未找到,在链表尾部插入新节点,并检查是否需要树化。
4. 树化条件:当链表长度达到TREEIFY_THRESHOLD(默认8)并且数组长度≥MIN_TREEIFY_CAPACITY(64)时,链表转换为红黑树;否则,优先扩容。
5. 更新已存在的键值对:如果找到相同key的节点,根据onlyIfAbsent参数决定是否更新值,并返回旧值。
6. 扩容与回调:新增节点后,检查总节点数是否超过扩容阈值threshold,若超过则调用resize()方法扩容。afterNodeInsertion和afterNodeRemoval方法用于插入和删除节点后的回调。
get()方法实现:通过key的哈希值计算出数组中的桶位置,然后在这个位置的链表中进行遍历,查找是否存在与key相等的节点。
扩容机制(resize):当元素数量超过阈值threshold时,会进行数组的扩容操作,这个操作会创建一个新的数组,并将旧数组中的元素重新计算索引后放入新数组中。
二、ConcurrentHashMap并发实现
ConcurrentHashMap是线程安全的HashMap实现,它通过分段锁(Segmentation Locking)来实现高并发访问。在Java 8及以后版本中,ConcurrentHashMap基于数组+链表+红黑树的实现方式,已经不再使用分段锁,而是采用了一种新的并发策略。
关键属性包括:
- volatile Node<K,V>[] table; // 存储数据的数组
- volatile int sizeControl; // 控制大小和扩容的变量
put()方法实现:
1. 计算桶位置并尝试插入新节点。
2. 如果该位置为空,则直接使用CAS(Compare-And-Swap)操作设置节点。
3. 如果该位置已存在节点,则遍历链表或红黑树,找到key相同的节点并更新值,或者在链表尾部插入新节点。
4. 使用casTabAt()方法增加元素数量addCount()。
5. 如果需要扩容,则调用transfer()方法进行扩容操作。
为什么ConcurrentHashMap不允许null键值?
ConcurrentHashMap不允许null键值是因为它要区别对待键为null的情况和键不存在的情况。在多线程环境下,无法判断null值是由哪个线程插入的,这可能导致并发问题。因此,ConcurrentHashMap将null键值的引入视为API设计上的一个错误。
HashMap和ConcurrentHashMap的哈希扰动的区别:
HashMap在进行哈希计算时使用的是hash方法,而ConcurrentHashMap使用的是spread方法。spread方法加入了更多的位运算,可以更好地减少哈希冲突,同时在高位进行异或运算,有助于提高散列分布的均匀性。
获取某个桶tabAt()方法:
ConcurrentHashMap中的tabAt方法用于获取数组中某个索引位置的元素,这一过程是原子的,确保了线程安全。
典型问题示例:
1. 线程安全问题:在多线程环境下,多个线程同时进行put操作时可能会引起数据不一致的问题,ConcurrentHashMap通过分段锁或CAS操作解决这些问题。
2. 链表转红黑树的阈值:在Java 8中,当链表长度大于8且数组长度大于64时,链表会转化为红黑树以优化性能,这是一个平衡链表长度和红黑树性能的选择。
3. 高并发下的扩容问题:扩容是一个复杂且耗时的操作,ConcurrentHashMap设计了一种平滑扩容的机制,尽量减少扩容对性能的影响。
相关推荐










impression1116
- 粉丝: 70
最新资源
- 深入解析嵌入式软件测试的应用及其原理和组织形式
- Windows平台下使用javacomm20-win32.zip进行Java串口开发
- 清华IT培训XML基础与进阶PPT教程
- 掌握iBATIS:官方中文教程与开发指南精读
- 吉大JAVA程序设计第22讲:完整课件资源发布
- JavaScript异步访问:封装Ajax脚本与XML文档生成
- J2EE开发必需的jar包组件与库文件下载指南
- 掌握验证码实现:VS2005+C#的网站登录源码示例
- Word转PDF工具使用指南与介绍
- 探索编译原理课程设计的奥秘
- 基于Struts+Ajax+Hibernate的新闻管理系统设计与实现
- 通用JAR包在管理系统中的应用与共享
- 酒店管理系统功能概览与管理技巧
- MS OFFICE 2003 VBA开发官方文档精简版
- 打造特色网站:乡下人仿百度留言本V1.2功能介绍
- 深入解析ThreadX硬实时操作系统特点及应用领域
- 在线智商测试题源代码完整解析
- 免费旅游信息管理网站源代码下载
- 数字信号处理宝典:从基础到高级应用全方位指南
- 提升无障碍体验:屏幕文本朗读器2.0新功能解析
- DataGrid与GridView扩展: 客户端排序与列宽自定义
- skyeye平台下uCoII版本的运行方法及修改要点
- Java分页显示组件:在JSP中实现便捷分页与数据导出
- Tomcat插件TomcatPluginV32的详细介绍与使用