前言介绍:volatile和transient关键字

第一种实现:HashTable

第二种实现:Collections.synchronizedMap(map)

第三种实现:ConcurrentHashMap

前言介绍:volatile和transient关键字

volatile(易变的,不稳定的),作用:

volatile变量写入时:JVM会把该线程对应的本地内存私有拷贝变化强制刷新到主内存中去,并且会其他线程中的本地内存私有拷贝无效;

volatile变量读取时:强迫从主内存中重读该成员变量的值;JVM为了获得最佳速度,允许每个线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比(如下图)。volatile关键字就是告诉JVM,不要优化了,我是易变的,是在多线程中访问的成员变量,如果是synchronized代码块中变量,或者最终常量,那么就不需要volatile

根据1,2两点特性,volatile变量控制多个线程读写,同时操作主存,是不是绝对线程安全了呐?答案是NO,可以肯定如果是 volatile int count = 1; 在多个线程中操作count = 2;这种原子操作是线程安全的;相反:一些读写复合操作 count++,会先读取count,然后加一,最后赋值count。只依靠volatile就不行了,AtomicInteger是采用CAS(compare and swap)机制,实现无锁线程安全。

禁止指令重排序优化

首先指令重排序优化是什么?

重排序是对代码指令的执行顺序重拍:比如说,a=1;b=3;,JVM可能会重排序为先b=3;a=1;如果fun和run并发执行,最终b可能是2或者3

transient(短暂的,临时的),作用:

先说说Serializable接口是赋予对象可序列化和反序列化的。transient修饰的变量,序列化到文件中对应的值为NOT SET

第一种实现:HashTable

核心思想synchronized修饰所有方法体

从put方法可以看出,不允许key,value为空

第二种实现:Collections.synchronizedMap(map)

源码发现,核心点在于final Map m;是一个指针指向传入的map参数,并且这个指针是不可改变的,如果后续令map = null;并不影响这个final变量的指向;Object mutex(互斥体)使用synchronized获取这个互斥体变量的占有,确保了多线程安全

下图注释1操作是把map1指针指向的Map对象清空,syncmap1指向的Map对象也清空了,所以去除是null;注释1操作是把map2指针清空,并不影响syncmap2已经记录了指向的Map对象

第一种和第二种实现在put和get会争夺锁,如果大量读取和写入并不在同一段?那么就引出了第三种实现

第三种实现:ConcurrentHashMap

JDK7容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁

JDK8实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap

因为锁力度降低到单个node,所以使用synchronized来控制锁,synchronized关键字也是官方一直在JVM底层持续优化,效率更高

val和next都会在扩容时发生变化,所以加上volatile来保持可见性和禁止重排序

弱化后的Segment:

java的map线程安全吗_Java中Map线程安全实现相关推荐

  1. java中实现线程的方法_Java中实现线程的方法

    Java中有几种方法可以实现一个线程?用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用? 第一种:继承Thread类 new Thread(){}.start();这表示调 ...

  2. java中map怎么取值_java中map的取值

    package com.itcast.map; import java.util.HashMap; import java.util.Map; import java.util.Set; import ...

  3. java中map的遍历方法_Java中Map的三种遍历方式

    集合中的三种遍历方式,如下代码: import java.util.Collection; import java.util.HashMap; import java.util.Iterator; i ...

  4. java中创建两种线程的方式_java中创建线程的两种方式有什么区别?

    *** 一.创建线程 1.继承Thread类 定义类继承Thread, 重写run()方法, 将线程中要执行的代码写在run()方法中 创建该类对象, 调用start()方法就可以开启一条新线程, 新 ...

  5. java创建线程几种_java中创建线程有几种方式

    详细内容 线程的创建方式 1.继承Thread类实现多线程 2.覆写Runnable()接口实现多线程,而后同样覆写run().推荐此方式 3.使用Callable和Future创建线程 相关视频教程 ...

  6. java多层map嵌套取值_java中map的多层遍历

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 Map> testmap=new HashMap>();Map user1=new HashMap();user1.put(1, (float ...

  7. map java 用法_java中map 9种常规用法

    通常来说,Map是一个由键值对组成的数据结构,且在集合中每个键是唯一的.下面就以K和V来代表键和值,来说明一下java中关于Map的九大问题. 0.将Map转换为List类型 在java中Map接口提 ...

  8. java map 自动排序_Java中Map的排序

    Map的种类 在Java中,Map的主要作用是存储键值对.由于是根据键得到值,所以不允许键重复.它主要有如下几个类别: HashMap: 最常用的Map,它根据键的HashCode值存储数据,根据键可 ...

  9. java用循环给map里面存值_Java中如何遍历Map对象的4种方法

    方法一 在for-each循环中使用entries来遍历 这是最常见的并且在大多数情况下也是最可取的遍历方式.在键值都需要时使用. 1 Map map = new HashMap();2 3 for ...

最新文章

  1. Java实战equals()与hashCode()
  2. 【django】全局上下文
  3. MySql数据同步FEDERATED引擎
  4. 计算机网络技术专业的规划,计算机网络技术专业建设规划
  5. docker 安装 mysql和Navicat Premium 远程连接
  6. c语言cis,c语言小白学习历程第五篇
  7. 我的Delphi开发经验谈
  8. 信号与系统——四对时域频域对应关系
  9. 职称计算机考试相当于几级,全国职称计算机考试与全国计算机等级考试有什么不同?...
  10. 蓝桥杯:调和级数————Python
  11. yocto系列讲解[理论篇]68 -Yocto版本信息查询稳定版本和EOL版本
  12. 5G是什么? --5G
  13. 错误 1error LNK1207 PDB 格式不兼容;请删除并重新生成
  14. 记生产一次弱引用对象引起的空指针异常
  15. 手机里可以学习钢琴的软件APP
  16. 计算机类智能问答助手论文,写论文不用愁,AI 来当小助手
  17. C++多线程helloWord
  18. 华为认证 HCIA-IoT V1.0 (物联网工程师)考试大纲
  19. 什么是 BA ?BA怎么样?BA和BI是什么关系?
  20. 机器学习之Logistic回归(逻辑蒂斯回归)

热门文章

  1. go与python的前景_未来几年Python就业前景如何
  2. nginx中斜杠(/)详解
  3. 腾讯官方送福利,5 款限定红包封面 限时领!
  4. 8.2更换用户手机号
  5. PMP 项目管理 考前专题(01)考试技巧 策略总结
  6. Java方法的基本用法
  7. Unity屏幕适配解决方案
  8. jspXCMS安装实践
  9. What is my IP?
  10. 鸿蒙系统用在手机上,全球第三大手机系统“鸿蒙”上线,这19款手机能抢先用...