hashmap为何是线程非安全的,hashmap线程不安全以及解决办法

  hashmap为何是线程非安全的,hashmap线程不安全以及解决办法

  00-1010前言如何处理哈希值冲突?hashmap的put方法不是线程安全的实现。

  00-1010总感觉对HashMap很熟悉,但是最近连续被问了几个关于它的问题,才发现它其实并不简单。下面总结一下关于它的一些问题,希望你能有个参考。

  00-1010都知道是基于哈希值的存储结构,可以在常量时间内消化。它广泛用于各种情况下的高效键值存储。这里有几个问题。首先,有哈希值冲突怎么办?相信很多人会不假思索的说话,通过链表解决冲突。将哈希值相同值存储到安装在该位置的链表中。但这又引出了一个新的问题。如果给定一个键,它的哈希值冲突,那么它如何从链表中得到预期的值?这取决于hashmap的存储结构。每个键值都将被封装到一个实体中,这个实体实际上存储在map中。这存储了值和密钥。链表中的所有值只需要比较键是否相等。又来了一个问题,为什么建议重写key的equal和hash方法?重写哈希方法可以确保不同的对象用于不同的哈希值,从而减少冲突。重写equal可以确保在冲突的情况下没有错误覆盖。

  

目录

final V putVal(int hash,K key,V value,boolean onlyIfAbsent,boolean evict) { NodeK,V[]tab;NodeK,V p;int n,I;If((tab=table)==null (n=tab . length)==0)//如果没有初始化,需要初始化,resize()方法n=(tab=resize())。初始化时也会调用lengthif((p=tab[I=(n-1)hash])==null)tab[I]=new node(hash,key,value,null);//这个位置没有值,所以直接插入重写hash方法的功能体现在这里else {//有冲突NodeK,V e;K kif(p . hash==hash((k=p . key)==key (key!=空键。equals(k)))//发现值e=p为键等于;Else if (p instanceof TreeNode)//事件树节点,插入树中。当jdk8中的冲突节点数达到一定值时,采用树形结构存储E=((treenode k,v) p)。puttreeval (this,tab,hash,key,value);else { for(int bin count=0;bin){//总是找到链表的末尾,将k-v插入if((e=p . next)==null){ p . next=new node(hash,key,value,null);if(bin count=tree ify _ 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) { //键V oldValue=e.value的现有映射;如果(!onlyIfAbsent old value==null)e . value=value;afterNodeAccess(e);返回旧值;} } modCountif(大小阈值)resize();afterNodeInsertion(驱逐);返回null}上面的代码充分演示了键重写equal的作用。HashMap是通过key的值来获取值的,所以一定要保证同一个键的hashcode不能随时更改。这就是为什么建议key是不可变的对象,比如string对象。如果键是一个对象,在操作过程中由于其内部值的改变而改变了键的hashcode,那么映射中的值将永远丢失。

 

  00-1010以上是关于kv的讨论,接下来是另一个关于HashMap的常见话题,——线程安全。大多数人都知道它是线程安全的。但是如果我问你它的非线程安全在哪里,恐怕一群人就难了。

  首先,我们很容易想到多线程插入中的冲突。多个线程同时插入,但其中一些值又会发生冲突。插的时候大家看到这个位置没有价值,就都插了,这样肯定会有价值覆盖,外在表现就是价值流失。如果在插入开始时这个位置已经有一个值,在插入链表的过程中,这个值仍然会被覆盖。

  另一个是同步膨胀。因为HashMap在空间不足的时候会自动扩展,所以大小会变成之前的两倍。同时,将以前的值复制到新数组中。冲突也会被复制。如果多个线程插入,并发现需要同时调整容量,它们都会调用resize方法。那么底楼到了之后会发生什么就很难预料了。

  所以这是HashMap非线程安全性的第二个体现。当然,当同时读取和写入一个值时,数据可能与预期不一致。这也是非线程安全的一种表现。

  以上是HashMap的一些相关问题。个人经验还是需要注意细节的。只有阅读源代码,才能有更深的体会。

  更多关于Hashmap的非线程安全的信息,请关注popular IT的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: