首页 » Web前端 » php源码hashmap技巧_看完这篇终于搞懂HashMap的源码了

php源码hashmap技巧_看完这篇终于搞懂HashMap的源码了

访客 2024-11-28 0

扫一扫用手机浏览

文章目录 [+]

看完脑图,个中很多还是不足详细的。
只是概述了内容。
HashMaphashMap的概述

hashMap,继续Map凑集,以key-value形式存储,个中key可以为null ,value是可以重复,其数据是无序的,且会在扩容的时候发生改变。

hashMap在进行存储的时候的步骤链表转红黑树在1.8的时候,hashMap加用了红黑树的数据构造,当某一数组的某一个位置hash冲突达到8个的时候,就会将链表转为红黑树,其缘故原由便是提高插入和查找的效率,利用链表的插入尾节点的效率是o(n),而利用了红黑树的话插入和查找都是O(logn)我们来看一下详细的插入流程:

php源码hashmap技巧_看完这篇终于搞懂HashMap的源码了

JDK1.7和1.8的扩容触发条件:数组长度X负载因子(默认0.75)达到这个数值时在1.8会直打仗发扩容,而在1.7会涌现再判断一个这个节点是否有占用,如果没有就插入,有的话就扩容1.7和1.8 的时候在扩容的时候会将新建一个为原数组两倍的数组,1.7将原数组中的hash进行重新打算hash加入到新数组,然后将hash碰撞的链表数据,以头插法进行插入到新的数组上,然后移动。
这个过程在并发情形下会有可能涌现循环依赖的情形,导致无限循环耗尽CPU。
而1.8 如果这个打算出来的hash值在原有数组位置+旧数组长度则放在新的数组上的这个原有数组位置+旧数组长度上面,新数组没有则放在原来的位置上,新的插入的数据

php源码hashmap技巧_看完这篇终于搞懂HashMap的源码了
(图片来自网络侵删)
hash打算的办法1.8如果key为null的话就放在第一个数组的下标为0的位置。
如果不为先打算出hashCode,再将hashCode 无符号右移,忽略符号位,空位都以0补齐。
然后再进行异或运算。

static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }12341.7 的打算办法将打算出来的hash值和数组的长度减1进行与运算,打算出来

static int indexfor(int h,int length) {// 个中的legth-1 也是为什么 hashMap的容量为2的n次幂的缘故原由return h & (length-1);}1234

从上面的两种通过hash值打算数组下表位置index的办法都可以将打算出来的值在数组length的长度内。
至于那种性能更高速率更快,散列的空间更加均匀,那毋庸置疑,肯定1.8里面的。

上面说到可负载因子是0.75,为什么默认的负载因子是0.75呢?个人理解:首先0.75 会用作扩容,这个值越大直到1,那扩容的次数是不是概率越低,hash冲突是不是越小?由于他这个值决定了达到多大值就会扩容。
如果设置一个0.1,那么在第一次存储完成后就扩容了,那肯定第二次进行打算hash的时候由于数组很大,那也就降落了hash碰撞。
我的理解便是在扩容次数和hash冲突之间起到一个平衡的浸染jdk1.7 中的注讲授明:作为一样平常规则,默认负载因子(0.75)在韶光和空间本钱上供应了很好的折衷。
较高的值会降落空间开销,但提高查找本钱(表示在大多数的HashMap类的操作,包括get和put)。
设置初始大小时,该当考虑估量的entry数在map及其负载系数,并且只管即便减少rehash操作的次数。
如果初始容量大于最大条款数除以负载因子,rehash操作将不会发生。
jdk 1.8中 :空想状态下,在随机哈希值的情形,对付loadfactor = 0.75 ,虽然由于粒度调度会产生较大的方差,桶中的Node的分布频率服从参数为0.5的泊疏松布。
hash冲突的几种办理办法开放定址法从发生冲突的那个单元起,按照一定的次序,从哈希表中找到一个空闲的单元。
然后把发生冲突的元素存入到该单元的一种方法。
链地址法(拉链法)hashMa也便是用的这种办法链接地址法的思路是将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第i个单元中,查找、插入和删除紧张在同义词链表中进行。
链表法适用于常常进行插入和删除的情形。
再哈希法便是同时布局多个不同的哈希函数:Hi = RHi(key) i= 1,2,3 … k;当H1 = RH1(key) 发生冲突时,再用H2 = RH2(key) 进行打算,直到冲突不再产生,这种方法不易产生聚拢,但是增加了打算韶光。
既然已经看了hashMap的源码我们再联系一下线程安全的hashMap都有哪些呢ConcurrentHashMap不用说我们都知道concurrentHahMap是线程安全版的hashmap ,其底层源码与hashMap类似,但是在数据构造上改变了一下,加了一个sagment[] ,这个sagement工具数组里面有多个小的hashMap,在进行操作的时候会对sagment进行加锁,让其同步实行。
由于当sagment里面hashMap越多的时候那么这个并发安全系数就越低,以是在ConcurrentHashMap里面有一个并发安全系数。
来掌握sagment里面的hashMap的数量。
其上面的说法是jdk1.7版本,这个锁采取的是rentrantLock。
但是在JDK1.8中利用的是更细粒度的锁利用Sychronized和CAS来进行枷锁。
1.8中的一个列子

1.7中的sagement[]//get方法是不加锁的,所有共享变量都是通过volatile润色的,确保或许最新值

public V get(Object key) { Segment<K,V> s; HashEntry<K,V>[] tab; int h = hash(key); long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null && //获取volatile (tab = s.table) != null) { for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile //获取volatile (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); e != null; e = e.next) { K k; if ((k = e.key) == key || (e.hash == h && key.equals(k))) return e.value; } } return null; }1234567891011121314151617HashTableHashTable也是hashMap的线程安全版本,由于自身性能的问题,也一贯没有被优化,以是其版本一贯没改变。
HashTable是给其各个方法加了sychronized关键字所有的实行都会同步实行。
hashTable慢的相对付ConcurrentHashMap来说。

标签:

相关文章

介绍百度码,技术革新背后的智慧之光

随着科技的飞速发展,互联网技术已经成为我们生活中不可或缺的一部分。而在这个信息爆炸的时代,如何快速、准确地获取信息,成为了人们关注...

Web前端 2025-01-03 阅读1 评论0

介绍皮箱密码,开启神秘之门的钥匙

皮箱,作为日常生活中常见的收纳工具,承载着我们的珍贵物品。面对紧闭的皮箱,许多人却束手无策。如何才能轻松打开皮箱呢?本文将为您揭秘...

Web前端 2025-01-03 阅读1 评论0

介绍盗号器,网络安全的隐忧与应对步骤

随着互联网的快速发展,网络安全问题日益突出。盗号器作为一种非法工具,对网民的个人信息安全构成了严重威胁。本文将深入剖析盗号器的原理...

Web前端 2025-01-03 阅读1 评论0