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 ...
随机推荐
- How to extract pcd from a rosbag? 如何从rosbag中提取pcd
4.1 bag_to_pcd Reads a bag file, saving all ROS point cloud messages on a specified topic as PCD fil ...
- 【转】tnsping不通,则需设置TNS_ADMIN环境变量
源地址:http://blog.csdn.net/pan_tian/article/details/7699599
- sap abap 流水号设置
1.TCODE:SNRO,进入如图所示界面 2. 短文本和长文本用来说明这个编号范围对象,输入任意描述即可. 子对象数据元素我们这里不填.这里需要说明一下,所谓子对象,多数指一个组织结构,比如公司代码 ...
- s5pv210移植Minigui3.0.12
移植平台:ubuntu:14.04 开发板:s5pv210(A8) Minigui版本:3.0.12-------------------------------------------------- ...
- Opencv常用函数讲解
1.approxPolyDP(Mat(ps), poly, 5, true);//根据点集,拟合出多边形 2.fillConvexPoly(mask, Mat(ps), Scalar(255));根据 ...
- arcgis10.0直连sde
- TP框架中D方法和M方法
D()和M()方法的区别: D和M的区别主要在于 M方法不需要创建模型类文件,M方法不会读取模型类,所以默认情况下自动验证是无效的,但是可以通过动态赋值的方式实现 而D方法必须有创建模型类. 我们可以 ...
- ansible部署,规划
部署管理服务器 第一步:先检查有没有ssh服务 [root@iZm5eeyc1al5vzh8bo57zyZ ~]# rpm -qf /etc/init.d/sshd openssh-server-5. ...
- my26_Slave failed to initialize relay log info structure from the repository
重启了一下从库,忘记先stop slave ,直接mysqladmin shutdown关闭实例,结果起不来了 mysql> start slave;ERROR 1872 (HY000): Sl ...
- 24-----BBS论坛
BBS论坛(二十四) 24.1.编辑板块 cms/js/banners.js $(function () { $('.edit-board-btn').click(function () { var ...