东辰安华学习网专业分享各种生活知识、常识,和大家一起共勉!

当前位置:首页 > 求职


hashmap为什么线程不安全(hashmap为什么不是线程安全的)

2023-10-18 10:35:30栏目:商业
TAG: 安全  不安

大家好,今天来为大家分享hashmap为什么线程不安全的一些知识点,和hashmap为什么不是线程安全的的问题解析,大家要是都明白,那么可以忽略,如果不太清楚的话可以看看本篇文章,相信很大概率可以解决您的问题,接下来我们就一起来看看吧!

本文目录

  1. concurrenthashmap怎么保证线程安全
  2. hashmap为什么不是线程安全的
  3. 写个例子说明HashMap线程不安全
  4. hashmap是线程安全还是不安全的

concurrenthashmap怎么保证线程安全

每个操作都是原子操作,都带锁的,保证一个成员同一时间只被一个方法调用

hashmap为什么不是线程安全的

原因:

JDK1.7中,由于多线程对HashMap进行扩容,调用了HashMap#transfer(),具体原因:某个线程执行过程中,被挂起,其他线程已经完成数据迁移,等CPU资源释放后被挂起的线程重新执行之前的逻辑,数据已经被改变,造成死循环、数据丢失。

JDK1.8中,由于多线程对HashMap进行put操作,调用了HashMap#putVal(),具体原因:假设两个线程A、B都在进行put操作,并且hash函数计算出的插入下标是相同的,当线程A执行完第六行代码后由于时间片耗尽导致被挂起,而线程B得到时间片后在该下标处插入了元素,完成了正常的插入,然后线程A获得时间片,由于之前已经进行了hash碰撞的判断,所有此时不会再进行判断,而是直接进行插入,这就导致了线程B插入的数据被线程A覆盖了,从而线程不安全。

写个例子说明HashMap线程不安全

谢谢邀请!下面介绍一下jdk1.7的扩容死循环问题!

HashMap扩容的源代码如下:

resize扩容方法中最重要的代码如下:

resize扩容步骤如下:

根据newCapacity生成一个数组。

遍历旧的数组,然后对其中的每一个值进行hash,重新进行插入。

修改扩容的阀值:threshold。

下面我们分别展示在单线程和多线程的环境的扩容

我们定义的Map为Map<Integer,String>

单线程环境下的扩容

我们先定义有个简单的hash,hash=key%length

默认hash表的长度为2,插入的元素为5911

5%2=1;

9%2=1;

11%2=1;

三个元素都碰撞在下标为1的位置上。

下面我们扩容到4:

5%4=1;

9%4=1;

11%4=3;

扩容步骤如下:

并发环境下的扩容

首先线程1和线程2同时扩容

线程1和线程2的e为5。e.next=9

但是此时,线程1由于调度问题暂停执行。

线程2继续执行,执行结束后如下:

这时,线程1被唤醒了。这时线程1的e为5,e.next=9;

此时:

处理完5后,我们就要处理9。

此时

因为在线程2中9的下一个节点为5,所以还要继续处理5,会把5放到线程1的table[1]处,

这时就会循环生成一个循环列表。11这个元素时无法加入到线程1里面了。

hashmap是线程安全还是不安全的

String,Interger这样的wrapper类作为HashMap的键是再适合不过了,而且String最为常用。

因为String是不可变的,也是final的,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。不可变性是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。不可变性还有其他的优点如线程安全。如果你可以仅仅通过将某个field声明成final就能保证hashCode是不变的,那么请这么做吧。因为获取对象的时候要用到equals()和hashCode()方法,那么键对象正确的重写这两个方法是非常重要的。如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这样就能提高HashMap的性能。

关于hashmap为什么线程不安全到此分享完毕,希望能帮助到您。