为什么说hashmap是线程不安全的_map线程不安全

为什么说hashmap是线程不安全的_map线程不安全 hashMap线程不安全的原因及表现hashMap出现线程不安全的原因:HashMap的实现里没有锁的机制,因此它是线程不安全的。其实只要有锁的机制,可以通过锁实现线程安全,我们在读写HashMap对象的时候加锁,以保障这个对象的线程安全,但不代表HashMap本身是线程安全的,因为是外力(你自己加的锁)使然。为啥不在HashMap内部加锁让它变成线程安全?这…

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

Jetbrains全系列IDE稳定放心使用

hashMap出现线程不安全的原因:

HashMap的实现里没有锁的机制,因此它是线程不安全的。

其实只要有锁的机制,可以通过锁实现线程安全,我们在读写HashMap对象的时候加锁,以保障这个对象的线程安全,但不代表HashMap本身是线程安全的,因为是外力(你自己加的锁)使然。

为啥不在HashMap内部加锁让它变成线程安全?
这样会增加单线程访问的资源消耗,即使没有多线程访问,也要每次检查、加锁、解锁。
实际上有线程安全的Map,Collections里面有个静态方法可以返回一个线程安全版本的HashMap

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {

return new SynchronizedMap<K,V>(m);
}

另外java5之后还提供了ConcurrentHashMap类,提供更高效的线程安全操作。

hashMap出现线程不安全的表现:
表现1:

多个线程同时操作一个hashmap就可能出现不安全的情况:

比如A B两个线程(A线程获数据 B线程存数据) 同时操作myHashMap

1.B线程执行存放数据

modelHashMap.put(“1″,”2”);

2.A线程执行get获取数据

modelHashMap.get(“1”)

A线程获取的值本来应该是2,但是如果A线程在刚到达获取的动作还没执行的时候,

线程执行的机会又跳到线程B,此时线程B又对modelHashMap赋值 如:modelHashMap.put(“1″,”3”);

然后线程虚拟机又执行线程A,A取到的值为3,这样map中第一个存放的值 就会丢失。。。。。

要保证值的准确,就要保证操作的原子性,就是保证A操作从头开始不能被打断。。所有要用同步关键字,或者使用java 1.5中的current新包中的ConcurrentHashMap,这是线程安全的,在java最新的并发包中,对之前非线程安全的工具,如hashMap List 都做了同步封转。

表现2:

一般我们声明HashMap时,使用的都是默认的构造方法:HashMap<K,V>,看了代码你会发现,它还有其它的构造方法:HashMap(int initialCapacity, float loadFactor),其中参数initialCapacity为初始容量,loadFactor为加载因子,而之前我们看到的threshold = (int)(capacity * loadFactor); 如果在默认情况下,一个HashMap的容量为16,加载因子为0.75,那么阀值就是12,所以在往HashMap中put的值到达12时,它将自动扩容两倍,如果两个线程同时遇到HashMap的大小达到12的倍数时,就很有可能会出现在将oldTable转移到newTable的过程中遇到问题,从而导致最终的HashMap的值存储异常。

表现3:

构造entry<K,V>单链表时,也会出现不安全的情况。

原文: https://blog.csdn.net/VIP_WangSai/article/details/70182933

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

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

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


相关推荐

  • webpack 多线程_webpack打包原理优化

    webpack 多线程_webpack打包原理优化happyPack多线程打包如何实现多线程打包?安装happypacknpmihappypack改造webpack.config.js,实现多线程打包jsletHappyPack=require(‘happypack’);module.exports={…module:{rules:[…

    2022年8月31日
  • 基于Spring MVC + Spring + MyBatis的【医院就诊挂号系统】[通俗易懂]

    基于Spring MVC + Spring + MyBatis的【医院就诊挂号系统】[通俗易懂]一、语言和环境1.实现语言:JAVA语言。2.环境要求:MyEclipse/Eclipse+Tomcat+MySQL。3.使用技术:SpringMVC+Spring+MyBatis或JSP+Servlet+JavaBean+JDBC。二、实现效果实现能够对患者姓名,医师类别、科室的模糊查询,用户点击核销以后状态变为已就诊。点击挂号实现基本信息的添加三、实现代码数据库:SETFOREIGN_KEY_CHECKS=0;———-

    2022年10月6日
  • windows 运行jar包 生成日志_jar包双击运行

    windows 运行jar包 生成日志_jar包双击运行1.创建运行的cmd脚本新建记事本startup.txt@echooff@rem需要运行的服务名字全称参数例:ljd-stream-msvs.jar->名字全称:ljd-stream-msvssetSERVICE_NAME=%1@rem运行的服务jar包目录路径setSERVICE_JAR_DIR=D:\MyWorks\IdeaProgramFiles\LjdProgramFiles\IfmsWorks\ljd-ifms-cloud\ljd-stream-ms

    2022年10月4日
  • mysql启动命令 linux命令,linux下mysql 启动命令

    mysql启动命令 linux命令,linux下mysql 启动命令1,使用service启动、关闭MySQL服务servicemysqlstartservicemysqlstopservicemysqlrestart运行上面命令,其实是service命令去找/etc/init.d下的相关的mysql脚本去执行启动、关闭动作。2,使用/etc/init.d/mysql启动、关闭MySQL服务,[root@DB-Serverbin]#/etc/in…

    2022年5月21日
  • send()、sendto()和recv()、recvfrom()的使用

    send()、sendto()和recv()、recvfrom()的使用udp通讯中的sendto()需要在参数里指定接收方的地址/端口,recvfrom()则在参数中存放接收发送方的地址/端口,与之对应的send()和recv()则不需要如此,但是在调用send()之前,需要为套接字指定接收方的地址/端口(这样该函数才知道要把数据发往哪里),在调用recv()之前,可以为套接字指定发送方的地址/端口,这样该函数就只接收指定的发送方的数据,当然若不指定也可,该函数就可以

    2022年7月23日
  • 补码的运算方法「建议收藏」

    补码的运算方法「建议收藏」负数在计算机中是用补码的形式存储的,正数在计算机中是用原码的形式存储的。正数求原码直接将十进制转二进制即可,负数的补码是在原码的基础上除符号位外其余位取反后+1。但是用这种方式求负数补码用编程实现不太方便,下面介绍一种用编程实现起来较简便的求负数补码的方法:1.求出负数绝对值的原码2.从原码的最后一位数码位往前数,当遇到第一个1时停在此位置3.将第一个1前面的数码全部求反…

    2022年9月23日

发表回复

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

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