美文网首页
ConcurrentHashMap

ConcurrentHashMap

作者: 秋笙fine | 来源:发表于2019-02-17 23:37 被阅读0次

    java.util.concurrent包下的ConcurrentHashMap是fail-safe的,安全失败
    而java.util包下的集合类是fail-fast的,快速失败。在使用迭代器的时候,快速失败的集合类是会抛出ConcurrentModificationException异常,而安全失败的迭代器不会。
    举例:ArrayList是快速失败的案例,如果在多线程下迭代,迭代器hashNext是判断是否有下一个元素,next用于返回当前元素并把指针指向下一个元素,如果是多线程情况下,利用CAS,会先获取容器的计数器modCount是否与此时相等,如果不相等,说明被修改过,会派出如上异常。

    ConcurrentHashMap对put方法的改进:
    ConcurrentHashMap底层仍然是散列表+红黑树。
    JDK1.7引入了Sement分段锁,这是一个继承了可重入锁的对象锁。
    与HashMap的put不同的是,我们在根据key的HashCode找到table中的下标之前,将整个哈希表分为了一个的segement数组,每个segement都占有一部分的table数组+哈希桶,当某一个线程访问某个segment的时候,获得锁,并不影响别的线程访问其它segment,我们只需要在put方法最后,释放这个segment锁即可。

    JDK1.8对ConcurrentHashMap进行了脱胎换骨的构造。引入了CAS,弃用了Segment锁。
    我们将当前key定位出的Node/Entry使用volatile关键字修饰,保证了可见性以及防止编译器优化造成的指令重排。利用CAS尝试写入,失败则自旋保证成功。因而步骤为:

    1. 根据key计算出hashCode
    2. 定位到table的下标,落槽,找到哈希桶中的位置,然后判断是否可以写入数据,如果为空,尝试利用CAS写入(HashMap是判断如果为空,直接写入的),这样防止了数据丢失,如果哈希槽长度大于8,生长为红黑树。如果当前位置的hashcode==Moved==-1,则需要进行扩容。如果都不满足,则用synchronized锁写入数据(红黑树/链表写入)

    get()方法和hashmap没有多大区别:
    仍然是根据key计算出来的hashCode寻址(位运算哈希),如果在桶上就直接返回值。
    对节点进行判断,如果是树节点,红黑树遍历,如果不是,链表遍历。

    总结:

    底层结构是:散列表+红黑树,这一点和HashMap是一样的。
    Hashtable是将所有的方法使用synchronized锁同步,效率低下,而ConcurrentHashMap是通过只在写入数据的使用使用sucnhronized锁+CAS实现原子性操作来保证线程安全的。CAS算法也可以算是乐观锁的一种。
    ConcurrentHashMap的key和value都不能为null。

    相关文章

      网友评论

          本文标题:ConcurrentHashMap

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