zoukankan      html  css  js  c++  java
  • 【Java】【HashMap】JDK1.7中ConcurrentHashMap是如何解决调用size时的一致性问题呢?

    • 再调用【size()】时,会出现什么样的一致性问题呢?

    1》在没有put的情况下,调用concurrentHashMap的size()方法,可以直接获取到表的长度

    2》在线程A调用size()方法的同时,线程B试图PUT了一个数据,那么线程A如何保证size()结果一致性呢?

    • 当然,JDK设计人员一定也想到了这个问题,官方源码如下:
    public int size() {
        // Try a few times to get accurate count. On failure due to
       // continuous async changes in table, resort to locking.
       final Segment<K,V>[] segments = this.segments;
        int size;
        boolean overflow; // true if size overflows 32 bits
        long sum;         // sum of modCounts
        long last = 0L;   // previous sum
        int retries = -1; // first iteration isn't retry
        try {
            for (;;) {
                if (retries++ == RETRIES_BEFORE_LOCK) {//5.判断尝试次数是否尝试最大值
                    for (int j = 0; j < segments.length; ++j)//6.对所有segment加锁,然后重新统计
                        ensureSegment(j).lock(); // force creation
                }
                sum = 0L;
                size = 0;
                overflow = false;
                for (int j = 0; j < segments.length; ++j) {//1.遍历所有Segment
                    Segment<K,V> seg = segmentAt(segments, j);
                    if (seg != null) {
                        sum += seg.modCount; //3.把segment的修改次数累加起来
                        int c = seg.count; //2.把segment的元素数量累加起来
                        if (c < 0 || (size += c) < 0)
                            overflow = true;
                    }
                }
                if (sum == last)//4.判断segment总修改书是否大于上一次修改数
                    break;
                last = sum;
            }
        } finally {
            if (retries > RETRIES_BEFORE_LOCK) {
                for (int j = 0; j < segments.length; ++j)
                    segmentAt(segments, j).unlock();//7.释放锁,统计结束
            }
        }
        return overflow ? Integer.MAX_VALUE : size;
    }
    • 单看源码一定很抽象,我们简述一下源码流程吧:

    1》遍历所有的Segment。

    2》把Segment的元素数量累加起来。

    3》把Segment的修改次数累加起来。

    4》判断所有Segment的总修改次数是否大于上一次的总修改次数。如果大于,说明统计过程中有修改,重新统计,尝试次数+1;如果不是。说明没有修改,统计结束。

    5》如果尝试次数超过尝试最大值,则对每一个Segment加锁,再重新统计。

    6》由于已经加锁,上一次修改次数和本次修改次数一定相等;然后释放锁,统计结束

    • 总结一下设计思想:

    整体流程成可以抽象理解成是由乐观锁转向悲观锁的一个过程。

    先不锁住所有Segment,而是乐观的假设调用size()过程不会有修改。

    当尝试一定次数依然有修改的话,才会悲观的将所有Segment锁住,从而保证强一致性。

  • 相关阅读:
    java的内部编码
    visual studio 快捷键
    C# ref和out总结
    C#函数3递归
    链表操作 两个链表间的相交性问题
    链表操作 有环链表问题
    链表操作 模拟问题
    链表操作 未排序链表的处理问题
    jjQuery 源码分析1: 整体结构
    jQuery 源码分析3: jQuery.fn/ jQuery.prototype
  • 原文地址:https://www.cnblogs.com/boluopabo/p/13031509.html
Copyright © 2011-2022 走看看