美文网首页
HashMap 与ConcurrentHashMap

HashMap 与ConcurrentHashMap

作者: 司徒伯明 | 来源:发表于2020-08-03 23:24 被阅读0次

    先来说HashMap
    HashMap实现原理
    开始时数组加链表
    对象的hashCode 会对应数组的一个元素
    初始容量 DEFAULT_INITIAL_CAPACITY = 1 << 4
    加载因子 DEFAULT_LOAD_FACTOR = 0.75f;
    扩容阈值 threshold ==>超过就会扩容
    在构造函数中 判断了初始化量的合理性
    在put 的时候inflatetable()
    hash 散列的位扰动
    头部节点插入法

    扩容的过程的循环,有死循环产生的

    java7 之后hashMap 是使用红黑树实现 节点中超过8个元素就会改用红黑树

    首先,我这里强调,ConcurrentHashMap的设计实现其实一直在演化,比如在Java8中就发生了非常大的变化(Java7其实也有不少更新),所以,我这里将比较分析结构、实现机制等方面,对比不同版本的主要区别。

    早期ConcurrentHashMap,其实现是基于:
    分离锁,也就是将内部进行分段(Segment),里面则是HashEntry的数组,和HashMap类似,哈希相同的条目也是以链表形式存放。
    HashEntry内部使用volatile的value字段来保证可见性,也利用了不可变对象的机制以改进利用Unsafe提供的底层能力,比如volatileaccess,去直接完成部分操作,以最优化性能,毕竟Unsafe中的很多操作都是JVMintrinsic优化过的。

    https://blog.csdn.net/qq_35452961/article/details/99753827

    concurrentHashMap

    记录JAVA bug 的地方?
    https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6423457

    在构造的时候,Segment的数量由所谓的concurrentcyLevel决定,默认是16,也可以在相应构造函数直接指定。注意,Java需要它是2的幂数值,如果输入是类似15这种非幂
    值,会被自动调整到16之类2的幂数值。

    ConcurrentHashMap会获取再入锁,以保证数据一致性,Segment本身就是基于ReentrantLock的扩展实现,所以,在并发修改期间,相应Segment是被锁定的。
    在最初阶段,进行重复性的扫描,以确定相应key值是否已经在数组里面,进而决定是更新还是放置操作,你可以在代码里看到相应的注释。重复扫描、检测冲突
    是ConcurrentHashMap的常见技巧。

    下面我来对比一下,在Java 8和之后的版本中,ConcurrentHashMap发生了哪些变化呢?
    总体结构上,它的内部存储变得和我在专栏上一讲介绍的HashMap结构非常相似,同样是大的桶(bucket)数组,然后内部也是一个个所谓的链表结构(bin),同步的粒度要
    更细致一些。
    其内部仍然有Segment定义,但仅仅是为了保证序列化时的兼容性而已,不再有任何结构上的用处。
    因为不再使用Segment,初始化操作大大简化,修改为lazy-load形式,这样可以有效避免初始开销,解决了老版本很多人抱怨的这一点。
    数据存储利用volatile来保证可见性。
    使用CAS等操作,在特定场景进行无锁并发操作。
    使用Unsafe、LongAdder之类底层手段,进行极端情况的优化。

    相关文章

      网友评论

          本文标题:HashMap 与ConcurrentHashMap

          本文链接:https://www.haomeiwen.com/subject/ydqirktx.html