zoukankan      html  css  js  c++  java
  • ConcurrentHashMap

    ConcurrentHashMap与HashMap的实现方法类似,不同的是它采用的是分段锁的思想支持并发的操作,它是线程安全的。

    要了解ConcurrentHashMap,首先要了解Segment,一个Segment就相当于一个HashMap对象。与HashMap一样,Segment包含一个HashEntry数组,数组中的每个HashEntry既是一个键值对,也是一个链表的节点。在ConcurrentHashMap中,有2的N次方个Segment对象,他们共同保存在一个segments数组中。

    整个ConcurrentHashMap的结构如下:

    ConcurrentHashMap的并发读写的几种情况:

    1. 不同Segment之间写入是可以并发的
    2. 同一Segment的写和读是可以并发执行的
    3. 同一Segment的写是不可以并发执行的,原因在于Segment的写入时需要上锁的,对于同一个Segment的并发写入就会被阻塞。

     每一个Segment就像一个自治区,读写操作高度自治,Segment之间互不影响。不同的Segment的写入或者读是可以并发执行的,对于同一个Segment的一读一写也是可以并发执行的,但是同一Segment并发写入需要上锁,会被阻塞。都各自持有一把锁,ConcurrentHashMap当中每个Segment都各自持有一把锁,在保证线程安全的同时降低了锁的粒度,度高了并发度。

    ConcurrentHashMap的读写过程:

    • Get方法
    1. 通过key做Hash运算,得到hash值;
    2. 通过hash值,定位到对应的Segment对象;
    3. 再次通过hash值,定位到Segment的数组的具体位置。
    • Put方法
    1. 通过key做Hash运算,得到hash值;
    2. 通过hash值,定位到对应的Segment对象;
    3. 获取可重入锁;
    4. 再次通过hash值,定位到Segment的数组的具体位置;
    5. 插入或者覆盖HashEntry对象;
    6. 释放锁。

     ConcurrentHashMap在读写时都需要二次定位,首先定位到segment,之后定位到该segment的具体数组下标。

          由于ConcurrentHashMap中对每一个Segment都各自加锁,保证了多线程下的数据安全,那么在调用Size()的时候,解决一致性也是一个问题,Size方法的目的是统计ConcurrentHashMap的总的元素个数,要将每一个Segment内部的元素的个数都统计得到总数;但是,如在在刚刚统计结束的Segment中瞬间插入一个新的元素,那又怎么解决?

           其Size方法是一个嵌套循环。

    1. 遍历所有的Segment。
    2. 把Segment的元素数量累加起来。
    3. 把Segment的修改次数累加起来。
    4. 判断所有Segment的总修改次数是否大于上一次的总修改次数。如果大于,说明统计过程中有修改,重新统计,尝试次数+1;如果不是。说明没有修改,统计结束。
    5. 如果尝试次数超过阈值,则对每一个Segment加锁,再重新统计。
    6. 再次判断所有Segment的总修改次数是否大于上一次的总修改次数。由于已经加锁,次数一定和上次相等。
    7. 释放锁,统计结束。

         为了尽量不锁住所有Segment,首先乐观地假设Size过程中不会有修改(CAS)。当尝试一定次数,才无奈转为悲观锁,锁住所有Segment保证强一致性。

  • 相关阅读:
    CriminalIntent项目开发笔记(二)
    CriminalIntent项目开发笔记(一)----动态添加Fragment
    android应用中去掉标题栏的方法
    15个IT程序员必须思考的问题
    Android Studio快捷键
    Android 学习笔记
    win7系统安装方法
    jquery随学随记
    接口功能测试策略--转载
    测试随笔
  • 原文地址:https://www.cnblogs.com/128-cdy/p/12977411.html
Copyright © 2011-2022 走看看