当前位置: 首页 > article >正文

ConcurrentHashMap 的 size()方法是线程安全的吗?为什么

ConcurrentHashMap 的 size()方法是非线程安全的。也就是说,当有线程调用 put 方法在添加元素的时候,其他线程在调用 size()方法获取的元素个数和实际存储元素个数是不一致的。原因是 size()方法是一个非同步方法,put()方法和 size()方法并没有实现同步锁。

put()方法

put()方法的实现逻辑是:在 hash 表上添加或者修改某个元素,然后再对总的元素个数进行累加。
其中,线程的安全性仅仅局限在 hash 表数组粒度的锁同步,避免同一个节点出现数据竞争带来线程安全问题。(如图)数组元素个数的累加方式用到了两个方案:
  • 当线程竞争不激烈的时候,直接用 cas 的方式对一个 long 类型的变量做原子递增。
  • 当线程竞争比较激烈的时候,使用一个 CounterCell 数组,用分而治之的思想减少多线程竞争,从而实现元素个数的原子累加。

size()方法

size()方法的逻辑就是遍历 CounterCell 数组中的每个 value 值进行累加,再加上baseCount,汇总得到一个结果。所以很明显,size()方法得到的数据和真实数据必然是不一致的。因此从 size()方法本身来看,它的整个计算过程是线程安全的,因为这里用到了 CAS的方式解决了并发更新问题

总结 

但是站在 ConcurrentHashMap 全局角度来看,put()方法和 size()方法之间的数据是不一致的,因此也就不是线程安全的。之所以不像 HashTable 那样,直接在方法级别加同步锁。在我看来有两个考虑点:
  • 直接在 size()方法加锁,就会造成数据写入的并发冲突,对性能造成影响,当然有些朋友会说可以加读写锁,但是同样会造成 put 方法锁的范围扩大,性能影响极大!
  • ConcurrentHashMap 并发集合中,对于 size()数量的一致性需求并不大,并发集合更多的是去保证数据存储的安全性。

http://www.kler.cn/a/107300.html

相关文章:

  • Shell 脚本中的大小写陷阱:为什么 ${PWD} 而不是 ${pwd}?
  • 【AutoGen 】简介
  • 安装SQL server中python和R
  • 在JPA和EJB中用乐观锁解决并发问题
  • StructuredStreaming (一)
  • Java面向对象高级2
  • 程序生活 - 减肥小记
  • C复习-指针
  • WPF:自定义按钮模板
  • xxl-job-架构及原理
  • 【24种设计模式】单例模式(Singleton Pattern)
  • 基于MATLAB的电流、电压互感器特性的仿真分析
  • 数据库MySQL(六):事务
  • vue + html + Lodop打印功能
  • 归结原理、归结演绎推理
  • Qt中设置鼠标透明度的应用及示例
  • 计网小题题库整理第一轮(面向期末基础)(3)
  • Spring Boot Actuator 介绍
  • (二开)Flink 修改源码拓展 SQL 语法
  • 数据结构 | 算法的时间复杂度和空间复杂度【详解】
  • Android---Bitmap详解
  • 【计网 Socket编程】 中科大郑烇老师笔记 (九)
  • 基于单片机的温湿度检测及远程控制系统设计
  • rest参数
  • STM32 CubeMX配置USB HID功能,及安装路径
  • 【Python机器学习】零基础掌握SimpleImputer缺失值填充