赞
踩
是Map接口的实现,双列集合,由<K,V>键值对组成,底层没有实现锁机制,其线程是不安全的,多线程环境下会出现数据覆盖问题,所以多线程不推荐使用HashMap,可以使用ConcurrentHashMap。
HashMap由多个Node组成,Node包括hash、key、value、next。
树化规则
HashMap里面定义了一个常量TREEIFY_THRESHOLD = 8,当链表长度超过树化阈值 8 时,先尝试调用resize()方法进行扩容来减少链表长度,如果数组容量已经 >=64(MIN_TREEIFY_CAPACITY),才会进行树化,Node节点转为TreeNode节点(TreeNode也是HashMap中定义的内部类)。
TreeNode除了Node的基本属性,还保存了父节点parent, 左孩子left,右孩子right,还有红黑树用到的red属性
扩容因子在统计学的计算下,并平衡空间利用率与时间利用率的前提下,提出为0.75,在.net开发中hashmap的负载因子为0.7
默认情况下,HashMap初始容量是16,负载因子是0.75
jdk1.7时,HashMap底层是由数组+单链表组成
此时,当数组长度大于size*负载因子且没有空位时,进行扩容,将数组的长度*2
jdk1.8时,HashMap底层得到优化,由数组+单链表+红黑树组成
jdk1.8的扩容分为两种情况:
1、当数组长度大于size*负载因子时触发扩容,新建一个两倍大小的数组
2、当数组长度还没超过阈值时,但链表长度达到8,此时,会进行扩容操作来resize,当数组大小达到64时,才会树化;数组大小达到64,HashMap就会停止扩容,而是树化来优化链表结构,提高查询效率,总之,当链表长度达到8,数组大小达到64时,才会进行树化操作
在jdk1.7中是基于segment分段的,每个segment下有一个HashMap,需要扩容时(超过size*负载因子),首先在segment下新建一个容量更大(两倍)的数组,将原数组下的链表及哈希值等内容赋值到新数组中,再改变segment的指针指向新数组。
1.8版本的ConcrrentHashMap不再基于segment,需要扩容时,直接新建一个容量更大的数组Entry,此时有多个线程同时向新数组进行复制赋值,每个线程负责一定的数量,另外,当某个线程在向此集合中put时,如果发现当前正在扩容,则该线程也加入扩容任务当中。如果某个线程put时,当前集合没有正在扩容,则将key-value加入到当前集合中,计算当前是否超过容量阈值,如果超过,则扩容。
1、1.8加入了红黑树,当链表长度达到8时,就会转化为红黑树,优化了插入和查询效率
2、1.7链表中插入元素使用的是头插法,而1.8插入元素时要判断链表的长度,需要遍历链表,所以改为采用尾插法。
3、1.7中哈希算法比较复杂,存在大量右移和异或运算,因为复杂的哈希算法的目的是要提高散列性(是指对象是否具有哈希值(Hash value)以及是否可以被用作哈希表(Hash table)的键值),1.8做出了优化,新增了红黑树,适当的简化了哈希算法,节约了系统资源。
流程如下:
树化源码:
- private final void treeifyBin(Node<K,V>[] tab, int index) {
- Node<K,V> b; int n, sc;
- if (tab != null) {
- //数组大小小于64,只扩容,不转化
- if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
- tryPresize(n << 1);
- //数组大小大于64,将Node转化为TreeNode
- else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
- synchronized (b) {
- if (tabAt(tab, index) == b) {
- TreeNode<K,V> hd = null, tl = null;
- for (Node<K,V> e = b; e != null; e = e.next) {
- TreeNode<K,V> p =
- new TreeNode<K,V>(e.hash, e.key, e.val,
- null, null);
- if ((p.prev = tl) == null)
- hd = p;
- else
- tl.next = p;
- tl = p;
- }
- //生成红黑树
- setTabAt(tab, index, new TreeBin<K,V>(hd));
- }
- }
- }
- }
- }
说到这里,HashMap和ConcurrentHashMap的基本数据结构和扩容机制就清晰了,这里还有一个重要的点,就是红黑树,这种数据结构十分重要,有兴趣的小伙伴可以关注我另一篇讲解红黑树的文章。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。