• 【Java面试题】ConcurrentHashMap的size()方法是线程安全的吗?为什么


    大家好,我是Mic,一个没有才华只能靠颜值混饭吃的Java程序员。

    一个工作了5年的粉丝,最近去蚂蚁面试,在第一面的时候,本问到了几个Java基础的问题。

    其中有一个问题比较有意思,面试官问:“ConcurrentHashMap的size()方法是线程安全的吗?为什么?”

    关于这个问题的高手回答,我整理到了一个10W字的面试文档里面,大家可以扫描文章尾端二维码领取。

    下面看看高手对这个问题的回答

    大家记得点赞、收藏加关注!

    高手:

    ConcurrentHashMap的size()方法是非线程安全的。

    也就是说,当有线程调用put方法在添加元素的时候,其他线程在调用size()方法获取的元素个数

    和实际存储元素个数是不一致的。

    原因是size()方法是一个非同步方法,put()方法和size()方法并没有实现同步锁。

    put()方法的实现逻辑是:在hash表上添加或者修改某个元素,然后再对总的元素个数进行累加。

    其中,线程的安全性仅仅局限在hash表数组粒度的锁同步,避免同一个节点出现数据竞争带来线程安全问题。

    数组元素个数的累加方式用到了两个方案:

    • 当线程竞争不激烈的时候,直接用cas的方式对一个long类型的变量做原子递增。

    • 当线程竞争比较激烈的时候,使用一个CounterCell数组,用分而治之的思想减少多线程竞争,从而实现元素个数的原子累加。

    size()方法的逻辑就是遍历CounterCell数组中的每个value值进行累加,再加上baseCount,汇总得到一个结果。

    所以很明显,size()方法得到的数据和真实数据必然是不一致的。

    因此从size()方法本身来看,它的整个计算过程是线程安全的,因为这里用到了CAS的方式解决了并发更新问题。

    但是站在ConcurrentHashMap全局角度来看,put()方法和size()方法之间的数据是不一致的,因此也就不是线程安全的。

    之所以不像HashTable那样,直接在方法级别加同步锁。在我看来有两个考虑点。

    1. 直接在size()方法加锁,就会造成数据写入的并发冲突,对性能造成影响,当然有些朋友会说可以加读写锁,但是同样会造成put方法锁的范围扩大,性能影响极大!

    2. ConcurrentHashMap并发集合中,对于size()数量的一致性需求并不大,并发集合更多的是去保证数据存储的安全性。

    总结

    关于这个问题,网上很多文章写得都很片面。

    导致大家在找资料学习的时候,很容易被这种不完整的理解误导。

    而且,这个问题切入的角度还挺有意思的,有些同学可能没往这个方向思考过。

    也导致无法很好的回答出来。

    另外,我将所有Java面试系列制作成了完整的面试文档。它的便捷之处在于,可以通过检索的方式,找到你想要的面试题,目前已经更新180期,总计超过15W字!

    【想领取面试文档的小伙伴可以点击文章底部名片无套路免费赠送给大家!】

    需要高手面试文档面试文档的小伙伴可以扫描下方二维码
    ↓↓↓↓↓↓↓↓↓↓↓↓↓

  • 相关阅读:
    Java 8实战(四)- Lambda类型推断与方法引用
    数据结构:二叉树的链式结构
    深入理解Prometheus: Kubernetes环境中的监控实践
    算网时代新思考,2023 移动云大会重磅来袭!
    Springboot实现人脸识别与WebSocket长连接的实现
    【AIGC未来的发展方向】面向人工智能的第一步,一文告诉你人工智能是什么以及未来的方向分析
    深入解析Java内存模型
    关于Google推出的AAB,你了解多少
    Mybatis防止Sql注入
    【网络安全篇】php伪协议-漏洞及其原理
  • 原文地址:https://blog.csdn.net/q331464542/article/details/126139417