HashMap源码详解与对比
前几天工作忙得焦头烂额时,同事问了一下关于Map的特性,刹那间懵了一下,紧接着就想起来了一些关于Map的一些知识,因为只要涉及到Collection集合类时,就会谈及Map类,因此理解好Map相关的知识是灰常重要的。
Collection集合类 与 Map类的层次结构,如下图:

Map是用来存储 Key-Value(K-V)键值对,且不允许Key重复。(JDK 1.8)
Map的子类包含Hashtable,HashMap,LinkedHashMap,TreeMap,EnumMap,J.U.C并发包下面包含ConcurrentHashMap,ConcurrentSkipListMap。
注:Hashtable是通过“synchronized”来实现同步,ConcurrentHashMap是通过“分段锁”来实现并发,ConcurrentSkipListMap是通过“跳表”来实现并发。
数据结构对比
JDK 1.7及之前,HashMap的底层是数组和链表结合使用,可以说其结构是单向链表构成的数组,即链表散列,又称拉链法,即数组中的每一个序列空间代表一链表,若在插入新元素时,如果哈希冲突,则将新的元素插入到冲突的序列空间的链表头部。

JDK 1.8之后,HashMap的底层是数组链表和二叉树结合使用,其结构是先以链表结构进行存储,如果当链表的节点数(阈值)大于等于8时,再将其转换为二叉树结构,若该二叉树结构的节点数大于64,则再次resize,触发rehash操作,重新分布节点。

JDK 1.7 | 1.8 HashMap 方法分析

1. hashmap在JDK1.7|1.8中hash()方法优化:此处参考博客链接_hashmap冲突的解决方法以及原理分析
其实关于hash优化以及为什么是2的次幂,能理解,但是总归没有辣么详细,所以就参考了其他博主的博客,如果不合适,还请提出,会进行删除的。

2. hashmap在JDK中resize()方法
当HashMap的长度超过临界值时(默认16*0.75=12),就会进行扩容。
通过调用resize()方法重新创建一个原HashMap大小的两倍的元素数组newTable,最大扩容到 MAXIMUM_CAPACITY = 1 << 30,并将原先table的元素全部移到newTable里面,重新计算hash,然后再重新根据hash分配位置。这个过程叫作rehash(最消耗性能的操作),因为它重新调用hash方法找到新的bucket位置。所以创建HashMap的时候,如果能预知元素个数,应尽量指定初始容量,这样可以提高HashMap的性能,避免重复resize()、rehash造成的性能损耗。
若在多线程情况下,多个线程同时出发resize()方法,会造成死循环操作

通过上面的解析,可以得到使用的是2次幂的扩展(指长度扩为原来2倍),所以,元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置。
因此,我们在扩充HashMap的时候,不需要像JDK1.7的实现那样重新计算hash,通过使用(e.hash & oldCap)来计算高位和低位的hash值,来把原来在一个槽位上面的链表拆分成两个链表即可。
有一点注意区别,JDK1.7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置,但是从上图可以看出,JDK1.8不会倒置。
3. hashmap线程不安全,效率高
HashMap线程是不安全的,如果在多线程环境下,会出现未知异常(谨记)。
如果要在多线程情况下使用Map,有以下几种可供选择:
①、使用Hashtable(类中方法全是synchronized,效率特低,没有过这种);
②、使用Collections.synchronizedMap(new HashMap(...));实现,但不建议使用,使用迭代器遍历的时候修改映射结构容易出错;
③、使用guava中ImmutableMap,它是线程安全的,且方便快捷的组装键值对(建议);
ImmutableMap<String, Integer> map1 = ImmutableMap.<String, Integer>builder().put("A", 1) .put("B"2) .put("C", 3) .build();
ImmutableMap<String, Integer> map2 = ImmutableMap .<String, String>of("X", 0);
④、使用java.util.concurrent.ConcurrentHashMap,采用分段锁(JDK1.7) / CAS(JDK1.8)、相对安全,效率高(建议);
4. hashmap其他方法解析
其他方法后续有时间在进行补充...
JDK 中 HashMap 的其他问题
暂未想到,如有错误,还请指正 ...
HashMap源码详解与对比的更多相关文章
- Java HashMap源码详解
Java数据结构-HashMap 目录 Java数据结构-HashMap 1. HashMap 1.1 HashMap介绍 1.1.1 HashMap介绍 1.1.2 HashMap继承图 1.2 H ...
- HashMap源码详解(JDK7版本)
一.内部属性 内部属性源码: //内部数组的默认初始容量,作为hashmap的初始容量,是2的4次方,2的n次方的作用是减少hash冲突 static final int DEFAULT_INITIA ...
- Shiro 登录认证源码详解
Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...
- Activiti架构分析及源码详解
目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...
- 源码详解系列(七) ------ 全面讲解logback的使用和源码
什么是logback logback 用于日志记录,可以将日志输出到控制台.文件.数据库和邮件等,相比其它所有的日志系统,logback 更快并且更小,包含了许多独特并且有用的特性. logback ...
- Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节
简介 这是 Mybatis 系列博客的第四篇,我本来打算详细讲解 mybatis 的配置.映射器.动态 sql 等,但Mybatis官方中文文档对这部分内容的介绍已经足够详细了,有需要的可以直接参考. ...
- vue 源码详解(二): 组件生命周期初始化、事件系统初始化
vue 源码详解(二): 组件生命周期初始化.事件系统初始化 上一篇文章 生成 Vue 实例前的准备工作 讲解了实例化前的准备工作, 接下来我们继续看, 我们调用 new Vue() 的时候, 其内部 ...
- RocketMQ源码详解 | Producer篇 · 其二:消息组成、发送链路
概述 在上一节 RocketMQ源码详解 | Producer篇 · 其一:Start,然后 Send 一条消息 中,我们了解了 Producer 在发送消息的流程.这次我们再来具体下看消息的构成与其 ...
- RocketMQ源码详解 | Broker篇 · 其一:线程模型与接收链路
概述 在上一节 RocketMQ源码详解 | Producer篇 · 其二:消息组成.发送链路 中,我们终于将消息发送出了 Producer,在短暂的 tcp 握手后,很快它就会进入目的 Broker ...
随机推荐
- jmeter - 录制web网页
1. 打开JMeter工具 创建一个线程组(右键点击“测试计划”--->“添加”---->“线程组”) 创建一个http代理服务器(右键点击“工作台”--->“添加”-- ...
- luogu1900 自我数
分享一个非正解的做法 本题解内存最低(\(\le1\rm MiB\)) 但是不开O2会tle 思路:每个数字仅会更新出1个新的数字,而且这个新数字比旧数字最多也就大70多.所以这里还是利用" ...
- Color Length UVA - 1625
题目大意: 给你两个字符串p,q,字符串中每个字符代表一个颜色,现在按顺序合并两个字符串,得到一个新字符串.新字符串的价值为,每个颜色价值的和,单个颜色价值的和等于该颜色在新字符中最后一次出现的位置减 ...
- 洛谷P2071 座位安排
题目背景 公元二零一四年四月十七日,小明参加了省赛,在一路上,他遇到了许多问题,请你帮他解决. 题目描述 已知车上有N排座位,有N*2个人参加省赛,每排座位只能坐两人,且每个人都有自己想坐的排数,问最 ...
- 【2014年百度之星资格赛1001】Energy Conversion
Problem Description 魔法师百小度也有遇到难题的时候—— 现在,百小度正在一个古老的石门面前,石门上有一段古老的魔法文字,读懂这种魔法文字需要耗费大量的能量和大量的脑力. 过了许久, ...
- mysql 配置utf8 编码,支持 emoji 方法!!!
utf8_general_ci 已经 过时了...请以后用mysql 考虑使用 utf8mb4, utf8mb4_unicode_ci!!! 兼容性更好. mysql的utf8编码的一个字符最多3个字 ...
- 学习C/C++需要掌握哪些知识
初级阶段 1.C语言 数据类型.变量.内存布局.指针基础: 字符串.一维数组.二维数组: 一级指针,二级指针,三级指针,N级指针概念,指针数组和数组指针: 结构体.文件的使用: 动态库的封装和设计: ...
- mariaDB 远程连接不上
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION; // %:表示从任何主机连接 ...
- Rabbitmq相关学习网址
1.安装文档: http://www.cnblogs.com/shuzhenyu/p/9823324.html 2.RabbitMq的整理 exchange.route.queue关系 https:/ ...
- 使用 maven 打包 src/test/java下的文件,并用 java jar 跑打包出来的jar
https://blog.csdn.net/nba_2011/article/details/71296745