首页
Python
Java
IOS
Andorid
NodeJS
JavaScript
HTML5
【
Java8 HashMap扩容时为什么不需要重新hash
】的更多相关文章
Java8 HashMap扩容时为什么不需要重新hash
技巧: 与&操作 和 与 n 如8 与,为0 则位置不变 https://blog.csdn.net/zlp1992/article/details/104376309 java8在实现HashMap时做了一系列的优化,其中一个重要的优化即在扩容的时候,原有数组里的数据迁移到新数组里不需要重新hash,而是采用一种巧妙的方法,代码如下: table = newTab; if (oldTab != null) { for (int j = 0; j < oldCap; ++j) {…
Java源码系列4——HashMap扩容时究竟对链表和红黑树做了什么?
我们知道 HashMap 的底层是由数组,链表,红黑树组成的,在 HashMap 做扩容操作时,除了把数组容量扩大为原来的两倍外,还会对所有元素重新计算 hash 值,因为长度扩大以后,hash值也随之改变. 如果是简单的 Node 对象,只需要重新计算下标放进去就可以了,如果是链表和红黑树,那么操作就会比较复杂,下面我们就来看下,JDK1.8 下的 HashMap 在扩容时对链表和红黑树做了哪些优化? rehash 时,链表怎么处理? 假设一个 HashMap 原本 bucket 大小为 16…
jdk1.7中hashmap扩容时不会产生死循环
在扩容时 transfer( ) 方法中 newTable 新数组 局部变量 table 旧数组 全局变量 当第一个链表进行while循环时 执行到 e.next = newTable[i]; 时 newTable[i]肯定为null. 导致 旧数组table 中 当前链表对象的next已经为null了 . 所以即使是多线程的情况下不会死循环…
HashMap、Hashtable、HashSet三种hash集合的区别
转载:http://www.cnblogs.com/lzrabbit/p/3721067.html#h1 HashMap和Hashtable的区别 两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,我们平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap(…
Java8中HashMap扩容算法小计
Java8的HashMap扩容过程主要就是集中在resize()方法中 final Node<K,V>[] resize() { // ...省略不重要的 } 其中,当HashMap扩容完毕之后,需要对原有的数据进行转移.因为容量变大了,部分元素的位置因此要变更,因而出现了下面的这个转移过程. 转移过程大致是:依次从旧数组里取值,然后从该值对应的链表上依次取出节点,对节点取模分别放入lo链表和hi链表,当链表中节点遍历完后,分别把lo链表和hi链表放入新数组的不同位置. 在看到如下第15行时,…
JDK1.8 HashMap 扩容 对链表(长度小于默认的8)处理时重新定位的过程
关于HashMap的扩容过程,请参考源码或百度. 我想记录的是1.8 HashMap扩容是对链表中节点的Hash计算分析. 对术语先明确一下: hash计算指的确定节点在table[index]中的链表位置index,不是节点的hash值. Node<K,V> loHead = null, loTail = null; //这两个是记录重新hash计算后仍在原位置(设为index)的节点 Node<K,V> hiHead = null, hiTail = null; //这两个是记…
java 基础 --- java8 HashMap
问题 : HashMap 容量大小 (capacity)为什么为 2n HashMap 是线程安全的吗,为什么 HashMap 既然有hash进行排位还需要equals()作用是什么 文章部分图片和代码来自参考资料,属于半原创 概述 HashMap 属于字典类,以键值对的方式存储值, 通过计算 hash 值,把key 放在特定的位置,当计算得到的键相同将会以链表的形式在冲突点链接, java 8 中当链表长度达到一定数量,该链表会形成一个红黑树,加快查找.所以java8 的HashMap内部…
JAVA8 HashMap 源码阅读
序 阅读java源码可能是每一个java程序员的必修课,只有知其所以然,才能更好的使用java,写出更优美的程序,阅读java源码也为我们后面阅读java框架的源码打下了基础.阅读源代码其实就像再看一篇长篇推理小说一样,不能急于求成,需要慢慢品味才行.这一系列的文章,记录了我阅读源码的收获与思路,读者也可以借鉴一下,也仅仅是借鉴,问渠那得清如许,绝知此事要躬行!要想真正的成为大神,还是需要自己亲身去阅读源码而不是看几篇分析源码的博客就可以的. 正文 HashMap是我们经常用的的一个集合类,其中…
Java8 HashMap详解
Java8 HashMap Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成. 根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n). 为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂…
Java8 HashMap源码分析
java.util.HashMap是最常用的java容器类之一, 它是一个线程不安全的容器. 本文对JDK1.8.0中的HashMap实现源码进行分析. HashMap使用位运算巧妙的进行散列并使用链地址法处理冲突. 自JDK1.8后, 若表中某个位置元素数超过阈值 则会将其自动转换为红黑树来提高检索效率. HashMap中的迭代器同样采用fail-fast机制, 即若迭代过程中容器发生结构性改变, 则会终止迭代. HashMap主要有三个视图接口keySet(), values(), entr…
【1】JDK8 HashMap扩容优化
JDK1.7 VS JDK1.8 比较 优化概述: resize 扩容优化 引入了红黑树,目的是避免单条链表过长而影响查询效率 解决了resize时多线程死循环问题,但仍是非线程安全的 这里主要讲讲扩容优化,死循环问题看笔记 扩容优化 下面我们讲解下JDK1.8做了哪些优化.经过观测可以发现,我们使用的是2次幂的扩展(指长度扩为原来2倍),所以,元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置.看下图可以明白这句话的意思,n为table的长度,图(a)表示扩容前的key1和key2两种…
jdk1.8 HashMap扩容原理详解
JDK1.7中,resize时,index取得时,全部采用重新hash的方式进行了.JDK1.8对这个进行了改善. 以前要确定index的时候用的是(e.hash & oldCap-1),是取模取余,而这里用到的是(e.hash & oldCap),它有两种结果,一个是0,一个是oldCap, 比如oldCap=8,hash是3,11,19,27时,(e.hash & oldCap)的结果是0,8,0,8,这样3,19组成新的链表,index为3:而11,27组成新的链表,新分配的…
HashMap扩容机制
1.什么是resize: resize就是重新计算容量:当我们不断的向HashMap对象里不停的添加元素时,HashMap对象内部的数组就会出现无法装载更多的元素,这是对象就需要扩大数组的长度,以便能装入更多的元素:当然Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组:就像我们用一个小桶装水,如果想装更多的水,就得换大水桶. 2.什么时候需要resize(): 当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值—即当前数组的长度乘以加载因子的值的时候…
Java中HashMap 初始化时容量(参数)如何设置合适?
问题引入 注:本文代码源自java 9. 阿里的插件对于初始化HashMap时,调用无参构造方法,提示如下: 那么问题来了,如果已知需要向 map 中 put n次,那么需要设定初始容量为多少? 单纯的我今天上午还认为是合理的容量是 n + 1 即可,直到看了源码: 应注意,map.size 获取的是当前map中键值对的个数,而不是容量. 当初始化的时候,没有指定容量,情况如何? 直接调用如下构造函数(无参) /** * Constructs an empty {@code HashMap} w…
阅读HashMap——jdk7时遇到的问题记录
今天看hashMapJDK7版,水很深,看的也痛苦~推一个博主:http://www.cnblogs.com/xrq730/ 看了源码,才发现自己基础真的很薄弱,虽然当初也是下了很多的经历,但是毕竟大学浪费了好多时间,底子自然也就不够,无厚积而又无薄发,自勉. 简单的一些总结: 1.基础知识回顾: a.位运算符:与或与亦或(源自百度) "按位异或"运算符,是双目运算. 按位异或运算符^ 逻辑运算均是按位进行操作,真值表如下: AND (位与&) OR ( 位或| ) XOR (…
HashMap扩容死循环问题
原文:https://blog.csdn.net/Leon_cx/article/details/81911223 下面我们来模拟一下多线程场景下扩容会出现的问题: 假设在扩容过程中旧hash桶中有一个单链表,单链表中只有一个节点A,也就是e引用的对象.新hash桶中有一个单链表,单链表中的节点是B->C,也就是newTable[i]引用的对象. 单线程扩容如果只有一个线程在执行扩容: - 执行到第 3 行next = e.next的时候next == null - 从第 5 行到第 9 行会将…
ArrayList && HashMap扩容策略
ArrayList扩容策略:默认10 扩容时是base + base/2, 即10 15 22 33 49...扩容时不安全:grow方法扩容时,赋值 elementData = Arrays.copyOf(elementData, newCapacity)时,若两个线程都进入这个地方,会导致快的赋值被慢的覆盖,导致跳号 HashMap扩容策略:容量默认16 loadFactor默认0.75 必须大于0容量扩容是16*2,若初始知道容量,也会resize为2的幂次大小,然后每次乘以2 loadF…
HashSet保证元素唯一原理以及HashMap扩容机制
一.HashSet保证元素唯一原理: 依赖于hashCode()和equals()方法1.唯一原理: 1.1 当HashSet集合要存储元素的时候,会调用该元素的hashCode()方法计算哈希值 1.2 判断该哈希值对应的位置上,是否有元素 1.3 如果该哈希值位置上没有元素,那么就直接存储该元素 1.4 如果该哈希值位置上有元素,那么就产生了哈希冲突 1.5 如果产生了哈希冲突,就得调用该元素的equals()方法,和该位置上的所有元素进行一一比较: 如果有任何一个元素与该元素相…
HashMap扩容后是否需要rehash?
需要,因为要重新计算旧数组元素在新数组地址.HashMap在JDK1.8中的rehash算法(也就是扩容后重新为里面的键值对寻址的算法)进行优化.hash寻址算法是 index =(n - 1) & hash 在JDK1.7的时候,是将数组扩容为两倍,然后将HashMap中所有的key重新进行hash寻址然后再放入到新的位置.在JDK1.8的HashMap的源码中,也将rehash算法最后寻址分为了两种情况: 扩容前,key1和key2的hash值不同,但是通过hash寻址算法后索引相同:扩容后…
HashMap扩容和ConcurrentHashMap
HashMap 存储结构 HashMap是数组+链表+红黑树(1.8)实现的. (1)Node[] table,即哈希桶数组.Node是内部类,实现了Map.Entry接口,本质是键值对. static class Node<K,V> implements Map.Entry<K,V> { final int hash; //用来定位数组索引位置 final K key; V value; Node<K,V> next; //链表的下一个node Node(int ha…
面试笔记--HashMap扩容机制
转载请注明出处 http://www.cnblogs.com/yanzige/p/8392142.html 扩容必须满足两个条件: 1. 存放新值的时候当前已有元素的个数必须大于等于阈值 2. 存放新值的时候当前存放数据发生hash碰撞(当前key计算的hash值换算出来的数组下标位置已经存在值) 如果需要扩容,调用扩容的方法resize() void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = ol…
关于JDK1.8 HashMap扩容部分源码分析
今天回顾hashmap源码的时候发现一个很有意思的地方,那就是jdk1.8在hashmap扩容上面的优化. 首先大家可能都知道,1.8比1.7多出了一个红黑树化的操作,当然在扩容的时候也要对红黑树进行重排,然而今天要说的并不是这个,而是针对数组中的链表项的处理优化. 关于hashmap的源码都十分精妙,有时间可以多看看. 首先上1.7的源码: void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = ol…
jdk1.7扩容时,不论是否有链表,并发都可能出现循环链表
扩容时使用transfertransfer不同于put时的判断hash冲突,直接使用头插法,如果没有冲突,则next为null.如下:e.next = newTable[i];newTable[i] = e;如果线程B设置了newTable[i] = e,线程A执行e.next = newTable[i]:则会造成e.next = e:不论是否有链表,都会造成死循环.…
为什么要指定HashMap的容量?HashMap指定容量初始化后,底层Hash数组已经被分配内存了吗?
为什么要指定HashMap的容量? 首先创建HashMap时,指定容量比如1024后,并不是HashMap的size不是1024,而是0,插入多少元素,size就是多少: 然后如果不指定HashMap的容量,要插入768个元素,第一次容量为16,需要持续扩容多次到1024,才能保存1024*0.75=768个元素: 所以你如果想插入个元素,你得需要指定容量,2048*0.75=1536>1000; 而HashMap扩容是非常非常消耗性能的,Java7中每次先创建2倍当前容量的新数组,然后再将老数…
JAVA8 HashMap 新特性
1. 链表解决冲突的方式: java中处理Hash散列后的冲突使用的是链表法: java8之前只是使用的简单Entry链表存储键值对.java8后,在Entry队列的长度大于8之后,会自动将队列转换成红黑树的存储,利用红黑树相对于链表更好的增改查效率来解决在出现较长链表时性能快速降低的问题. 图片来自美团技术团队 2. resize() 的方式: 随着hashMap中数据量的增多,槽不够用的时候需要使用resize来增大槽的容量.此时,需要将所有的数据根据hash值重…
什么是hashMap,初始长度,高并发死锁,java8 hashMap做的性能提升
问题1:HashM安排的初始长度,为什么? 初始长度是 16,每次扩展或者是手动初始化,长度必须是 2的幂. 因为: index = HashCode(Key) & (length - 1), 如果 length是 2的 幂的话,则 length - 1就是 全是 1的二进制数,比如 16 - 1 = 1111,这样相当于是 坐落在长度为 length的hashMap上的位置只和 HashCode的后四位有关,这只要给出的HashCode算法本身分布均匀,算出的index就是分布均匀的. 因为…
java8 HashMap源码 详细研读
HashMap原理 目的: 单纯分析和学习hashmap的实现,不多说与Hashtable.ConcurrentHashMap等的区别. 基于 jdk1.8 在面试中有些水平的公司比较喜欢问HashMap原理,其中涉及的点比较多,而且大多能形成连环炮形式的问题. 一般连环炮,一环不知道后面试官也就不问了,但是低层连环没连上,恭喜扣分是大大的,连到比较深的时候,说不知道还好点,比如: 关于集合的 1.1Hashmap是不是有序的? 不是继续 1.2有没有有顺序的Map? TreeMap…
java集合之hashMap,初始长度,高并发死锁,java8 hashMap做的性能提升
众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry.这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干. HashMap数组每一个元素的初始值都是Null. 对于HashMap,我们最常使用的是两个方法:Get 和 Put. 1.put方法的原理 比如调用 hashMap.put("apple", 0) ,插入一个Key为“apple"的元素.这时候我们需要利用一个哈希函数来确定Entry的插入位…
Java8 HashMap详解(转)
Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成. 根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n). 为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN). 来一…
HashMap 扩容 加载因子
HashMap: public HashMap(int initialCapacity, float loadFactor) { //初始容量不能<0 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); //初始容量不能 > 最大容量值,HashMap的最大容量值为2^30 if (initialCapa…