(5)HashMap原理解析——为啥线程不安全?

目录

一、 HashMap的数据结构

二、HashMap的功能实现源码解析

1. hash方法

2. 由链表改为红黑树

3.扩容

4. 扩容后的新位置

5. 搬家

三、 怎样将HashMap升级为线程安全的

1. HashMap为啥线程不安全呢?

2.  HashMap应该怎样实现线程安全呢?


一、 HashMap的数据结构

1.7版本与1.8版本数据结构的区别

    1.7版本使用的数据结构是数组 + 链表的形式。对于新增的节点使用的是头插法,新增的节点增加在离桶最近的地方。

    

1.8版本使用的是 数组 + 链表/红黑树的形式。新增节点使用的是尾插法,新增的节点在链表的尾部。当链表的长度>=8时,会转换为红黑树结构。

二、HashMap的功能实现源码解析

1. hash方法

    如果没有指明HashMap的初始化大小值,则其默认初始化大小是16。

    当我们有一个新的值被put方法放入HashMap时,它应该在0~15之间有一个具体的位置。那么应该用什么方法确定它的位置呢?

    我们常想到的就是用随机取模的方法来做,Random(16).nextInt(),简单粗暴。但是如果我们对同一个key比如"hello",反复地放入同一个HashMap,则其每次的位置都是随机的且位置不同,这样对于查找并不方便,最好用一种与key本身带有某种关系的算法,同一个key往往放在同一个位置。我们看下HashMap的源码是怎样确定key的位置的。

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        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 {
            ....
        }
    }

     源码的算法是 tab[i = (n - 1) & hash]

     tab是HashMap内部的Node数组,tab[i]就是第i个的位置。 i 的取值是(n-1) & hash。

     n -1 是数组的长度 - 1, 那么hash是什么呢?

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    它的计算原理是: ha

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值