解析为什么hashmap是线程不安全的?「建议收藏」

解析为什么hashmap是线程不安全的?「建议收藏」扩容一般我们声明HashMap时,使用的都是默认的构造方法:HashMap<K,V>,看了代码你会发现,它还有其它的构造方法:HashMap(intinitialCapacity,floatloadFactor),其中参数initialCapacity为初始容量,loadFactor为加载因子,扩容就是在put加入元素的个数超过initialCapacity*loa…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

  1. 扩容

一般我们声明HashMap时,使用的都是默认的构造方法:HashMap<K,V>,看了代码你会发现,它还有其它的构造方法:

HashMap(int initialCapacity, float loadFactor),

其中参数initialCapacity为初始容量,loadFactor为加载因子,扩容就是在put加入元素的个数超过initialCapacity * loadFactor的时候就会将内部Entry数组大小扩大至原来的2倍,然后将数组元素按照新的数组大小重新计算索引,放在新的数组中,同时修改每个节点的链表关系(主要是next和节点在链表中的位置)。

假设这里有两个线程同时执行了put()操作,并进入了transfer()环节:

解析为什么hashmap是线程不安全的?「建议收藏」

刚开始:

线程1中的e指向key(0),next指向key(4),此时线程1挂起。

 

解析为什么hashmap是线程不安全的?「建议收藏」

 

线程2调度完成所有节点的移动,移动后结果为:

解析为什么hashmap是线程不安全的?「建议收藏」

线程1继续执行,线程一会把线程二的新表当成原始的hash表,将原来e指向的key(0)节点当成是线程二中的key(0),放在自己所建table[0]的头节点。注意线程1的next仍然指向key(4),

虽然此时key(0)的next已经是null。

 

解析为什么hashmap是线程不安全的?「建议收藏」

  1. 执行e.next = newTable[i],于是 key(0)的 next 指向了线程1的新 Hash 表,因为新 Hash 表为空,所以e.next = null,
  2. 执行newTable[i] = e,所以线程1的新 Hash 表第一个元素指向了线程2新 Hash 表的 key(0)。好了,e 处理完毕。
  3. 执行e = next,将 e 指向 next,所以新的 e 是 key(4)

 

线程1的e指向了上一次循环的next,也就是key(4),此时key(4)的next已经是key(0)。将key(4)插入到table[0]的头节点,并且将key(4)的next设置为key(0)。此时仍然没有问题。

 

解析为什么hashmap是线程不安全的?「建议收藏」

  1. 现在的 e 节点是 key(4),首先执行Entry<K,V> next = e.next,那么 next 就是 key(0)了
  2. 执行e.next = newTable[i],于是key(0) 的 next 就成了 key(4)
  3. 执行newTable[i] = e,那么线程1的新 Hash 表第一个元素变成了 key(4)
  4. 执行e = next,将 e 指向 next,所以新的 e 是 key(0)

 

解析为什么hashmap是线程不安全的?「建议收藏」

  1. 现在的 e 节点是 key(0),首先执行Entry<K,V> next = e.next,那么 next 就是 null
  2. 执行e.next = newTable[i],于是key(0) 的 next 就成了 key(4)
  3. 执行newTable[i] = e,那么线程1的新 Hash 表第一个元素变成了 key(0)
  4. 执行e = next,将 e 指向 next,所以新的 e 是 key(4)

 

总结版:HashMap在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容数组中,在多线程的环境下,存在同时其他的元素也在进行put操作,如果hash值相同,可能出现同时在同一数组下用链表表示,造成闭环,导致在get时会出现死循环,所以HashMap是线程不安全的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183168.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Python win32api_python api文档

    Python win32api_python api文档本文整理汇总了Python中win32api.SetCursorPos方法的典型用法代码示例。如果您正苦于以下问题:Pythonwin32api.SetCursorPos方法的具体用法?Pythonwin32api.SetCursorPos怎么用?Pythonwin32api.SetCursorPos使用的例子?那么恭喜您,这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方…

    2022年10月11日
    1
  • pycharm安装配置环境_如何在pycharm中配置anaconda

    pycharm安装配置环境_如何在pycharm中配置anacondapycharm安装及配置(anaconda)pycharm的下载与安装jetbrains官网开发者工具找到pycharm下载专业版等待下载完成anaconda的下载与安装anaconda官网 滑到页面最下方选择合适的版本,开始下载双击开始安装这里选择所有用户或者仅自己都行这里勾选上添加环境变量,就不用自己配置了查看开始菜单安装成功安装配置pycharm双击以后再重启,直接finish启动pycharm这里需要进行一下激活,我这里就用

    2022年8月29日
    3
  • datagrip2020激活码【中文破解版】

    (datagrip2020激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月30日
    1.3K
  • 面试 设计题_设计模式面试题及答案

    面试 设计题_设计模式面试题及答案文章目录设计模式什么是设计模式为什么要学习设计模式设计模式分类设计模式的六大原则开放封闭原则(OpenClosePrinciple)里氏代换原则(LiskovSubstitutionPrinciple)依赖倒转原则(DependenceInversionPrinciple)接口隔离原则(InterfaceSegregationPrinciple)迪米特法则(最少知道原则)(Deme…

    2022年9月13日
    5
  • 什么是SOA架构?为什么使用SOA架构?

    什么是SOA架构?为什么使用SOA架构?SOA架构简介面向服务的架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种这样的系统中的服务可以以一种统一和通用的方式进行交互**SOA具有以下五个特征**1.可重用;2.松耦合;3.明确定义的接口;…

    2022年6月24日
    29
  • Idea激活码永久有效Idea2022.1激活码教程-持续更新,一步到位

    Idea激活码永久有效Idea2022.1激活码教程-持续更新,一步到位Idea激活码永久有效2022.1激活码教程-Windows版永久激活-持续更新,Idea激活码2022.1成功激活

    2022年6月17日
    16.2K

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号