Java8 HashMap 扩容机制与线程安全分析

本文详细分析了Java8 HashMap的构造函数、put方法、扩容机制resize()以及并发安全性。在扩容过程中,resize()不仅用于扩容,还负责初始化哈希表。在并发环境下,JDK1.7中HashMap扩容可能导致死循环,而JDK1.8通过改变数组引用关系避免了死循环,但可能造成键值对丢失。
摘要由CSDN通过智能技术生成

如果大家有仔细阅读过 HashMap 的源码就会发现 HashMap 的哈希表初始化并不是在其构造函数中进行的,而是 resize() 方法。

这篇文章不对 HashMap 中的树进行介绍。

一、HashMap 四个构造函数

这里把 HashMap 的四个构造函数全贴出来,主要是给大家一个参照。

PS:并不是所有的构造函数都初始化了 threshold,但是所有的构造函数都初始化了加载因子,另外初始容量大小也都没有初始化。

    // 构造函数 1 
    public HashMap(int initialCapacity, float loadFactor) {
   
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
    
    // 构造函数 2
    public HashMap(int initialCapacity) {
   
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
    
    // 构造函数 3
    public HashMap() {
   
        this.loadFactor = DEFAULT_LOAD_FACTOR; 
    }
    // 构造函数 4
    public HashMap(Map<? extends K, ? extends V> m) {
   
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

二、put 方法

我们都知道 HashMap 的底层是一个基于 Node<K,V>[] table 的数组,看完了上面的构造函数,我们发现数组并不是在构造函数中完成的,那是在哪里初始化的呢?带着这个疑问我们来看一下 HashMap 中的 put 方法。

    public V put(K key, V value) {
   
        return putVal(hash(key), key, value, false, true);
    }

    /**
     * Implements Map.put and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent 为 true 时不改变已经存在的值
     * @param 为 false 时表示哈希表正在创建
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
   
        /**
         * tab:哈希表数组
         * p:桶位置上的头节点
         * n:哈希表数组大小
         * i:下标(槽位置)
         */
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        // 当哈希表数组为 null 或者长度为 0 时,初始化哈希表数组
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        // 头节点为空直接插入(无哈希碰撞)
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        // 哈希碰撞
        else
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值