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()数量的一致性需求并不大,并发集合更多的是去保证数据存储的安全性。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值