hashmap非线程安全关于hash值冲突处理-亚博电竞手机版

目录

  • 前言
  • hash值冲突该怎么处理
    • hashmap的put方法
    • 非线程安全体现

前言

总是觉得对hashmap很熟悉,但最近连续被问到几个关于它的问题,才发现它其实并不简单。这里对关于它的一些问题做个总结,也希望能够大家一个参考。

hash值冲突该怎么处理

都知道它是基于hash值,可以进行常量时间消化的存储结构。广泛用于各种情况下的高效key-value存储。这里有几个问题。首先,如果出现hash值冲突该怎么处理?相信很多人都不用思考就能说出,通过链表来解决冲突。就是将hash值相同值存储到一个挂载在该位置的链表里面去。但是这就又引出了新的问题,给一个key,它的hash值有冲突的情况下,它是如何在链表上取到你所期望的value的?这个就要去看hashmap的存储结构了。每一个key-value会被封装到一个entity中,map中存储的其实是这个entity。这样既存储了value,又存储了key。所有在链表上取值只需要比较key是否equal。这里又出现了一个问题,为什么建议重写key的equal和hash方法。重写hash方法能够保证不同对象用于不同的hash值,从而减少冲突,重写equal则可以在出现冲突的情况下,保证不出现错误覆盖的情况。

hashmap的put方法

final v putval(int hash, k key, v value, boolean onlyifabsent, boolean evict) { nodehttp://www.cppcns.com;[] tab; node p; int n, i; if ((tab = table) == null || (n = tab.length) == 0)//没有初始化,则要初始化,初始化调用的也是resize()方法 n = (tab = resize()).lengthhttp://www.cppcns.com; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newnode(hash, key, value, null);//这个位置没有值,直接插入,重写hash方法的作用体现在这里 else {//出现了冲突 node e; k k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))//找恰卡编程网到了如该key equal的value e = p; else if (p instanceof treenode)//事树节点,插入到树里。jdk8冲突节点数目达到一定值后,使用树结构存储 e = ((treenode)p).puttreeval(this, tab, hash, key, value); else { for (int bincount = 0; ; bincount) {//一直找到链表的结尾,将k-v插入 if ((e = p.next) == null) { p.next = newnode(hash, key, value, null); if (bincount >= treeify_threshold - 1) // -1 for 1st treeifybin(tab, hash);//是否需要改成树存储 break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key v oldvalue = e.value; if (!onlyifabsent || oldvalue == null) e.value = value; afternodeaccess(e); return oldvalue; } } modcount; if ( size > threshold) resize(); afternodeinsertion(evict); return null; }

上面的代码充分表明了key重写equal的作用。hashmap以key的value来获取值,所以一定要确保同一个key的hashcode在任何时候都不能改变。这也是为什么建议key是不可变对象,如string对象。如果key是对象,运行过程中key的hashcode因为内部值的改变而发生了改变,那么map中的value将永远丢失。

非线程安全体现

以上是关于kv的讨论,接下来是关于hashmap的另外的一个常见话题——线程安全问题。多数人都知道它是非线程安全的。但是如果问你它非线程安全体现在哪里,恐怕会难住一批人。

首先容易想到的是多线程插入时出现了冲突的情况,多个线程同时插入,但是这其中有些值又出现了冲突。插入时大家都看到这个位置没有值,于是都进行插入,这样肯定会出现值覆盖,对外的表现就是值丢失。如果开始插入时,这个位置已经有了值,那么在插入链表过程中还是会出现值覆盖。

另外就是同时扩容问题。因为hashmap会在空间不足时自动扩容,大小变成之前的两倍。同时复制之前的值到新的数组中。冲突链也会进行复制。如果多个线程插入后同时看到容量需要调整,就都会调用resize方法。那么底层到达会出现什么问题就难以预测了。

所以这也是hashmap非线程安全的第二点体现。当然同时读写一个值也可能会存在数据跟期望不一致的情况。这也是非线程安全的表现。

以上就是hashmap的一些相关问题。个人体会还是需要注重细节,自己看源码,才会有更深入的体会。

更多关于hashmap非线程安全的资料请关注亚博电竞手机版其它相关文章!

展开全文
内容来源于互联网和用户投稿,文章中一旦含有亚博电竞手机版的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系亚博电竞手机版删除

最新文章

网站地图