精华内容
下载资源
问答
  • HashMap 扩容

    2019-03-06 17:26:15
    什么时候扩容: 当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值—即当前数组的长度乘以加载因子的值的时候,就要自动扩容啦。 存放新值的时候当前已有元素的个数必须大于等于阈值 存放新值的...

    什么时候扩容:

    当向容器添加元素的时候,会判断当前容器的元素个数,如果大于等于阈值—即当前数组的长度乘以加载因子的值的时候,就要自动扩容啦。
    存放新值的时候当前已有元素的个数必须大于等于阈值
    存放新值的时候当前存放数据发生hash碰撞
    (当前key计算的hash值换算出来的数组下标位置已经存在值)

    扩容(resize)

    重新计算容量,向HashMap对象里不停的添加元素,而HashMap对象内部的数组无法装载更多的元素时,对象就需要扩大数组的长度,以便能装入更多的元素。当然Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组,就像我们用一个小桶装水,如果想装更多的水,就得换大水桶。
    Hashmap的扩容需要满足两个条件:当前数据存储的数量(即size())大小必须大于等于阈值;当前加入的数据是否发生了hash冲突。
    因为上面这两个条件,所以存在下面这些情况
    (1)、就是hashmap在存值的时候(默认大小为16,负载因子0.75,阈值12),可能达到最后存满16个值的时候,再存入第17个值才会发生扩容现象,因为前16个值,每个值在底层数组中分别占据一个位置,并没有发生hash碰撞。
    (2)、当然也有可能存储更多值(超多16个值,最多可以存26个值)都还没有扩容。原理:前11个值全部hash碰撞,存到数组的同一个位置(这时元素个数小于阈值12,不会扩容),后面所有存入的15个值全部分散到数组剩下的15个位置(这时元素个数大于等于阈值,但是每次存入的元素并没有发生hash碰撞,所以不会扩容),前面11+15=26,所以在存入第27个值的时候才同时满足上面两个条件,这时候才会发生扩容现象。

    展开全文
  • HashMap扩容

    千次阅读 2017-01-24 11:54:31
    `HashMap`的size大于等于(**容量*加载因子**)的时候,会触发扩容的操作,这个是个代价不小的操作。 为什么要扩容呢?`HashMap`默认的容量是16,随着元素不断添加到`HashMap`里,出现`hash`冲突的机率就更高,那每个桶对应...

    概述


    HashMap的size大于等于(容量*加载因子)的时候,会触发扩容的操作,这个是个代价不小的操作。
    为什么要扩容呢?HashMap默认的容量是16,随着元素不断添加到HashMap里,出现hash冲突的机率就更高,那每个桶对应的链表就会更长,
    这样会影响查询的性能,因为每次都需要遍历链表,比较对象是否相等,一直到找到元素为止。

    为了提升查询性能,只能扩容,减少hash冲突,让元素的key尽量均匀的分布。


    扩容基本点


    加载因子默认值是0.75

    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    

    容量的默认值是16

     static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 等于16
    

    HashMap提供了一个构造参数,可以在创建的时候指定容量和加载因子。

     public HashMap(int initialCapacity, float loadFactor)
    

    默认的情况下,HashMapsize一旦大于等于16*0.75=12的话,
    同时每个Entry(或者叫桶)里面至少有一个元素的时候就会进行扩容。

    
     if ((size >= threshold) && (null != table[bucketIndex])) {
                resize(2 * table.length);
                hash = (null != key) ? hash(key) : 0;
                bucketIndex = indexFor(hash, table.length);
    }
    

    扩容的时候,容器容量翻倍

     resize(2 * table.length);

    扩容的时候需要重新计算元素的数组下标
    1、重新分配一个新的Entry数组
    2、重新计算原来元素的在新数组中的下标(比较耗资源)

    展开全文
  • hashmap 扩容

    2019-02-20 10:03:28
    1.7 先扩容 后插入新节点 1.8 先插入 后扩容

    1.7 先扩容 后插入新节点

    1.8 先插入 后扩容

    展开全文
  • HashMap扩容死锁

    千次阅读 2021-03-10 09:45:03
    HashMap扩容HashMap扩容transfer()函数原Entry数组转移到新Entry数组扩容死锁单线程扩容多线程扩容死锁 HashMap扩容 HashMap在JDK1.7使用的是数组+链表的方式,而在JDK1.8及以后则使用的是数组+链表+红黑树的方式...

    HashMap扩容

    HashMap在JDK1.7使用的是数组+链表的方式,而在JDK1.8及以后则使用的是数组+链表+红黑树的方式进行数据存储。本文主要是对JDK1.7中存在的死锁问题进行分析。

    transfer()函数

     /**
         * Transfers all entries from current table to newTable.
         */
        void transfer(Entry[] newTable, boolean rehash) {
            int newCapacity = newTable.length;
            for (Entry<K,V> e : table) {
                while(null != e) {
                    Entry<K,V> next = e.next;//第一行
                    if (rehash) {
                        e.hash = null == e.key ? 0 : hash(e.key);
                    }
                    int i = indexFor(e.hash, newCapacity);//第二行
                    e.next = newTable[i];//第三行
                    newTable[i] = e;//第四行
                    e = next;//第五行
                }
            }
        }
    

    第一行:记录oldhash表中e.next;
    第二行:rehash计算数组的位置;
    第三行:e要插入到链表的头部,所以要将e.next指向new hash的表中的第一个元素;
    第四行:将e放入到newTable当中;
    第五行:将e指向下一个节点。

    原Entry数组转移到新Entry数组

    数组的容量首先是2的指数次方大小,如果无构造参数,默认大小为16。当数组的大小超过扩容阈值的时候,就会扩容,一般扩容为之前的2倍。在JDK1.7中主要使用的是头插法的方式进行数组扩容。从原数组转移数据到新数组时,假设所有数据还是会落在同一索引下,那么同一链表下的数据的存储位置会发生反转,头变成尾,尾变成头。

    扩容死锁

    单线程扩容

    假设:hash的算法就是简单的key与length(数组长度)的求余。hash表的长度为2,如果不扩容,那么元素3,5,7按照计算(key%length)都应该碰撞到table[1]上。
    扩容:将hash表的长度将会变成4,然后重新计算hash。
    第一步:e指向key(3),next指向key(7);
    第二步:计算key(3)将会落在new[3]上面(3%4=3),将key(3)指向new[3],并将key(3)放到new[3];
    第三步:e指向key(7);
    第四步:next指向key(5);
    第五步:计算key(7)将会落在new[3]上面(7%4=3),key(7)的next指向key(3),采用头部插入法,将key(7)插入new[3];
    第六步:同上。直到e指向null跳出循环。
    在这里插入图片描述

    多线程扩容死锁

    假设有两个T1、T2线程同时put,同时进入到transfer()。
    Entry<K,V> next = e.next;代码块处,线程T2中断,此时T1线程执行完线程扩容,T2继续执行。
    第一步:e2和next2当前指向的位置为T1处的值;
    第二步::计算key(3)将会落在new2[3]上面(3%4=3),将key(3)指向new2[3],并将key(3)放到new[3],e2和next2指向key(7);
    第三步:next2指向key(7).next,也就是T2中的key(3),e2指向T1的key(7);
    第四步:将key(7)插入到T2的new[3]位置,根据e2 =next2,此时e2和next2都指向key(3);
    第五步:此时next2=e2.next,next2指向null,key(3)重新插入到T2-3中,key(3).next = key(7),此时e2指向null,形成闭环。

    在这里插入图片描述
    当再有新的key插入T2-3时,首先要判断当前key是否存在时,在for (Entry<K,V> e = table[i]; e != null; e = e.next)就会进入死循环。

    public V put(K key, V value) {
            if (table == EMPTY_TABLE) {
                inflateTable(threshold);
            }
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key);
            int i = indexFor(hash, table.length);
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }
    
            modCount++;
            addEntry(hash, key, value, i);
            return null;
        }
    

    JDK1.8对死锁的改进请见:HashMap扩容改进分析

    展开全文
  • HashMap扩容机制分析 在说HashMap扩容机制之前,有必要简述下HashMap的基本结构。以便各位更加清除的理解HashMap的底层是如何扩容的。HashMap自JDK1.8之后结构采用数组+单链表【单链表长度达到...
  • 主要介绍了java HashMap扩容详解及实例代码的相关资料,需要的朋友可以参考下
  • HashMap扩容流程

    2019-09-21 13:10:24
    HashMap的扩容,又被很多人叫rehash、重哈希,我本人是很反对这个叫法的,事实上HashMap扩容的时候,Node中存储的Key的hash值并没有发生变化,只是Node的位置发生了变化。 首先说为什么需要扩...
  • HashMap扩容以及ConcurrentHashMap扩容机制HashMap1.71.8ConcurrentHashMap1.71.8 HashMap 1.7 void transfer(Entry[] newTable) { // 1.7 的hashmap 数组+链表 // 获取到旧表 Entry[] src = table; // 获取...
  • 主要介绍了Java8 HashMap扩容算法实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • jdk7的HashMap扩容过程在多线程下容易形成环,线程不安全,那么怎么产生的环?要解决这个问题,就要先弄懂jdk7下的HashMap是怎么扩容的,这里先介绍扩容过程,然后分析环的形成过程。 2. 扩容过程 jdk7中,扩容代码...
  • HashMap扩容效率问题

    2021-03-30 16:13:23
    请问有谁研究过hashMap扩容这块的不?为啥在这种情况下,指定扩容大小的执行效率竟然小于默认大小的??试了10遍以上
  • HashMap扩容死循环问题

    千次阅读 2018-08-21 17:18:47
    下面这是JDK 1.7中HashMap扩容时调用的核心代码,作用是将原hash桶中的节点转移到新的hash桶中: void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = ...
  • HashMap扩容改进分析

    千次阅读 2021-03-10 16:59:47
    JDK1.8以后对之前版本的HashMap扩容多线程场景下的死锁的问题进行了解决。采用高低位拆分转移方式,避免了链表的产生。 resize()方法扩容部分 for (int j = 0; j < oldCap; ++j) { Node<K,V> e; if ((e =...
  • HashMap扩容原理

    2021-07-08 14:34:07
    三、HashMap扩容为什么总是2的次幂四、JDk1.7扩容死循环问题五、JDK1.8的新结构1.为什么非要使用红黑树呢?2.什么是红黑树?3.红黑树的特性 一、什么是HashMap? HashMap 数据结构为 数组+链表(JDk1.7),JDK1.8中...
  • 集合类:HashMap扩容机制集合类:HashMap扩容机制 集合类:HashMap扩容机制 扩容:hashMap的初始容量是16,默认扩容因子0.75.扩容因子可在new的时候通过构造方法设置。hashmap每次扩容大小为原大小的2倍。当hashmap...
  • HashMap扩容机制

    千次阅读 2020-11-28 17:06:54
    想要了解HashMap扩容机制你要有这两个问题 1.什么时候才需要扩容 2.HashMap扩容是什么 1.什么时候才需要扩容HashMap中的元素个数超过数组大小(数组长度)*loadFactor(负载因子)时,就会进行数组扩容,...
  • HashMap扩容机制(1.7/1.8)

    2021-03-18 16:47:26
    HashMap扩容机制(1.7/1.8) 当HashMap决定扩容时,会调用HashMap类中的resize(int newCapacity)方法,参数是新的table长度。在JDK1.7和JDK1.8的扩容机制有很大不同。 JDK1.7下的扩容机制 JDK1.7下的resize()方法是...
  • 2.hashmap扩容机制 创建一个新的newtab替代oldtab。然后数据迁移,但是1.7版本时才有头插入法。如下图(图是网上找的) 单线程: 1.7扩容代码 1 do { 2 //保留要转移指针的下一个节点 3 Entry<K,V> ...
  • 一、问题和背景 昨天面试腾讯被问到了HashMap为什么线程不安全,多线程下会有哪些线程不安全的情况...今天特意上网搜了一下答案,看到两篇博客觉得写得很有道理,深入浅出HashMap扩容死循环问题和JDK1.7和JDK1.8中H...
  • HashMap扩容为什么为2的次方幂 HashMap扩容为2的次方幂。 首先观察hashMap插入方法的代码第六行: final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; ...
  • Java基础——HashMap扩容2倍

    千次阅读 2019-01-13 20:20:45
    HashMap扩容2倍 在HashMap中,执行put方法时,会对添加的key进行运算得出对应的hash值,再根据hash值计算得出对应的hash桶坐标节点tab[i]。 if ((p = tab[i = (n - 1) &amp; hash]) == null) tab[i] = new...
  • HashMap在Java的使用中占据着很重要的地位,平时使用的时候,相信很多Java程序员都知道在定义HashMap的时候,给它设置一个初始容量,以便减少hashMap扩容(resize)带来的额外开销,比如像我同(zi)事(ji)的这段...
  • HashMap扩容代码片段分析 Hash扩容部分的代码,由于没有同步,可能发生循环链,导致查询出现严重问题 1. 源代码 void transfer(Entry[] newTable) { Entry[] src = table; //旧的Hash表赋给src int newCapacity ...
  • 待修改。。 一、扩容机制 HashMap是没有进行初始化容量,也就是现在是一个空的HashMap(容量为0),这是因为HashMap使用的懒加载机制。 HashMap就使用默认的初始化容量,也就是16...测试HashMap扩容机制:loadFacto...
  • 文章目录前言JDK7 HashMap扩容JDK8 HashMap扩容 前言 JDK7 和JDK8 的扩容方法都基于 resize()方法,但底层实现却有所不同 JDK7 HashMap扩容 void addEntry(int hash, K key, V value, int bucketIndex) { if (...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 67,671
精华内容 27,068
关键字:

hashmap扩容