Hashtable源码解析

    首先来一波对比,Hashtable与HashMap,这两个一看到,Hashtable是线程安全,put、remove、get、size、hashCode等方法都用了synchronized同步修饰符,而HashMap是非线程安全的。Hashtable很早(JDK1.0)就出现,从复杂度上来说,先研究一下Hashtable利于后续理解HashMap和ConcurentHashMap的设计。

    看源码个人习惯于从代码入口看起,Hashtable构造函数,如下图:

有四个构造函数,默认参数大小 11和0.75f(分别代表初始大小和加载因子,继续往下看)

    

    构造函数后,看到几个类变量成员,那这几个变量成员分别是啥,代表什么意思?

    table:数据存储结果,一个数组链表,读取和删除等操作速度在数组和链表折中(扩容后续讨论)。

    count:hashtable的元素数量,也就是hashtable大小。

    threshold:判断Hashtable是否需要扩容的临界值。

    loadFactor:加载因子,默认0.75,影响threshold的大小和扩容效率。

    modCount:Hashtable的修改次数。

    

    声明Hashtable实例后,则是put和get等操作:

    1、看看put函数做了啥,Hashtable的value不能为空即是这里第一行做了判断,而key为空时第453报错导致。至此,可以明白Hashtable为什么key和value都不能为null了。而后继续往下看。

        a)计算数组下表index,这里关注与table的length取余,后续扩容有影响。

        b)for循环比较简单,通过下标找到数组对应的链表,然后判断是否有对应的key存在,存在则更新value并返回旧值。

        c)执行addEntry新增元素。

    

    2、addEntry函数新增元素,主要是判断是否count>=threshold需要扩容,需要则扩容;count是Hashtable大小,而threshold是Hashtable当前分配大小乘以一个负载因素,数据在entry[]中的分布可能如下:

    可能1:entry[n],当前m个元素, 有m个链表,每个链表一个元素。(entry是一个数组链表的结构)

    可能2:entry[n],当前m个元素,只有一个链表,这个链表存了m个元素。

    可能3:entry[n],当前m个元素,有s(s<m)个链表,每个链表的元素数量>0。

    从以上三个可能的元素分布中,会发现极端情况可能2是有些链表的深度太大,操作效率会降低,此时合理做法是将元素重新分散hash到不同链表,以使链表元素分布均匀。

    遇到可能1的情况也是比较极端的,变成一个数组,就没有发挥链表的快速修改的优势。

    最合理的分布式是 可能3 ,所以,在设置加载因子loadFactor的时候需要考虑应用场景和数据分布,在数据量比较小的时候可能会频繁的rehash,随着数据量增长应该是散列分布(不排除数据key值都是递增的情况)。

    

    3、接下来看一下扩容rehash是怎么做的。

        a)新容量 newCapacity = (oldCapacity << 1) + 1(不越界的情况可以理解成oldCapacity * 2 + 1)。

        b)判断newCapacity 是否越界,如果越界而且原table数组已经是所允许的最大值,则什么都不做直接返回,否则扩容为最大值。

        c)新建一个newMap对象存储新table,更新扩容临界threshold的值。

        d)循环旧table的数组及其对应的链表,O(n)复杂度,重新hash计算index。

    

    4、相对而言,获取元素的时候就简单了,而且速度也是比较快的,因为通过hash快速获取数组下标从而取到子链表,后续只需要遍历子链表,相对单纯链表而言速度无疑读取效率提升许多。

    

    5、看看删除,毋庸置疑,删除也是很简单快速的,获取下标后遍历子链表,需要判断目标元素是链表头还是其他,就是移动一下引用而已,so easy。

    

    6、还有个比较有意思就是hashCode方法。在计算hashCode之前做了loadFactor = -loadFactor; 的操作标记正在计算hashCode,看得到是会做loadFactor 是否小于0的判断,不过有个疑惑就是这个函数不是已经有synchronize同步修饰了方法吗,也没到看其他地方用loadFactor做计算,后续再看看,留待评论。

    

    



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值