• LongAdder 源码分析


    LongAdder

    LongAdder 能解决什么问题?什么时候使用 LongAdder?

    1)LongAdder 内部包含一个基础值【base】和一个单元【Cell】数组。
    没有竞争的情况下,要累加的数会累加到这个基础值上;
    如果有竞争的话,LongAdder 会将要累加的数累加到 cell 数组的某个单元里面。
    所以整个 LongAdder 的值包括基础值和 Cell 数组中所有单元的值的总和。
    2)在竞争不激烈时,其性能类似与 AtomicLong,但是需要更多的存储空间;
    在竞争激烈时,其吞吐量要远高于 AtomicLong【以空间换时间】。
    

    如何使用 LongAdder?

    1)高并发场景下的多线程计数器
    

    使用 LongAdder 有什么风险?

    2)通过 sum 计算结果值时如果存在多线程写入,则其值可能是不精确的。
    

    LongAdder 核心操作的实现原理?

    创建实例

        /**
         * 创建一个累积和为 0 的 LongAdder 实例
         */
        public LongAdder() {
        }
    

    累加值

        /**
         * 原子累加指定的值 x 到 LongAdder
         */
        public void add(long x) {
            Cell[] cs; long b, v; int m; Cell c;
            /**
             * 1)如果 cells 为 null,则尝试原子更新值到 base 中
             * 2)如果 cells 不为 null,则将其累加到其中一个 cell 中。
             * if (!casBase(b = base, b + x)) {
             * 首先尝试原子更新值到 base 中,更新失败则将其累加到指定的 cell 中?
             * }
             */
            if ((cs = cells) != null || !casBase(b = base, b + x)) {
                /**
                 * 1)cells 为 null,并且原子更新 base 值失败,出现在第一次竞争发生时。
                 * 2)cells 不为 null
                 * cell 是否发生竞争的标记
                 */
                boolean uncontended = true;
                /**
                 * cells 不为 null &&
                 * 其长度大于 1 &&
                 * 基于当前线程的探测值定位的 cell 不为 null &&
                 * 则尝试原子更新目标 cell 值
                 */
                if (cs == null || (m = cs.length - 1) < 0 ||
                        (c = cs[Striped64.getProbe() & m]) == null ||
                        !(uncontended = c.cas(v = c.value, v + x))) {
                    /**
                     * 1)cell 为 null
                     * 2)原子更新目标 cell 值失败,即单个 cell 发生竞争
                     */
                    longAccumulate(x, null, uncontended);
                }
            }
        }
    
    Striped64#
        /**
         * 尝试原子更新 base 值
         */
        final boolean casBase(long cmp, long val) {
            return Striped64.BASE.compareAndSet(this, cmp, val);
        }
    
        final void longAccumulate(long x, LongBinaryOperator fn,
                boolean wasUncontended) {
            int h;
            // 探测值为 0
            if ((h = Striped64.getProbe()) == 0) {
                // 强制初始化当前线程的线程局部随机数
                ThreadLocalRandom.current(); // force initialization
                // 读取新的探测值
                h = Striped64.getProbe();
                // 发生 cell 竞争
                wasUncontended = true;
            }
            boolean collide = false;                // True if last slot nonempty
            done: for (;;) {
                Cell[] cs; Cell c; int n; long v;
                // 1)cells 已经完成初始化
                if ((cs = cells) != null && (n = cs.length) > 0) {
                    // 1-1)基于线程探测值定位的 cell 为 null
                    if ((c = cs[n - 1 & h]) == null) {
                        // 没有在执行扩容
                        if (cellsBusy == 0) {       // Try to attach new Cell
                            // 创建新的 Cell 并写入值
                            final Cell r = new Cell(x);   // Optimistically create
                            // 原子更新 cellsBusy
                            if (cellsBusy == 0 && casCellsBusy()) {
                                try {               // Recheck under lock
                                    Cell[] rs; int m, j;
                                    // 再次确认目标 cell 是否为 null
                                    if ((rs = cells) != null &&
                                            (m = rs.length) > 0 &&
                                            rs[j = m - 1 & h] == null) {
                                        // 写入新创建的 cell,操作完成
                                        rs[j] = r;
                                        break done;
                                    }
                                } finally {
                                    // 重置 cellsBusy
                                    cellsBusy = 0;
                                }
                                continue;           // Slot is now non-empty
                            }
                        }
                        collide = false;
                    }
                    /**
                     * 1)基于线程探测值定位的 cell 不为 null
                     * 2)发生 cell 竞争,则重置
                     */
                    else if (!wasUncontended) {
                        wasUncontended = true;      // Continue after rehash
                    // 尝试原子更新目标 cell 中的值,更新成功则退出循环
                    } else if (c.cas(v = c.value,
                            fn == null ? v + x : fn.applyAsLong(v, x))) {
                        break;
                    // cells 数组长度超出系统的 CPU 总数或发生 cells 扩容   
                    } else if (n >= Striped64.NCPU || cells != cs) {
                        collide = false;            // At max size or stale
                    } else if (!collide) {
                        collide = true;
                    // 尝试进行扩容
                    } else if (cellsBusy == 0 && casCellsBusy()) {
                        try {
                            if (cells == cs) {
                                // 容量扩大为原来的两倍
                                cells = Arrays.copyOf(cs, n << 1);
                            }
                        } finally {
                            cellsBusy = 0;
                        }
                        collide = false;
                        continue;                   // Retry with expanded table
                    }
                    // 基于伪随机数重新计算探测值
                    h = Striped64.advanceProbe(h);
                }
                // 2)未发生 cell 竞争 && cells 未扩容 && 原子更新 cellsBUsy 成功【表示当前 cell 正在写入值】
                else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {
                    try {                           // Initialize table
                        if (cells == cs) {
                            // 创建长度为 2 的 Cell 数组
                            final Cell[] rs = new Cell[2];
                            // 将目标值写入指定的 cell
                            rs[h & 1] = new Cell(x);
                            // 更新 cells table
                            cells = rs;
                            break done;
                        }
                    } finally {
                        // cells 创建完成,则重置标识
                        cellsBusy = 0;
                    }
                }
                // 3)尝试原子更新 base 值
                else if (casBase(v = base,
                        fn == null ? v + x : fn.applyAsLong(v, x))) {
                    // 更新成功则退出循环
                    break done;
                }
            }
        }
    

    其他操作

        /**
         * 原子累加 1
         */
        public void increment() {
            add(1L);
        }
    
        /**
         * 原子递减 1
         */
        public void decrement() {
            add(-1L);
        }
    
        /**
         * 读取 LongAdder 的总和,计算过程中未发生竞争则其值是精确的。
         */
        public long sum() {
            final Cell[] cs = cells;
            long sum = base;
            if (cs != null) {
                for (final Cell c : cs) {
                    if (c != null) {
                        sum += c.value;
                    }
                }
            }
            return sum;
        }
    
        /**
         * 只有在确保当前没有多线程竞争时,才应该调用该方法进行重置 LongAdder。
         */
        public void reset() {
            final Cell[] cs = cells;
            base = 0L;
            if (cs != null) {
                for (final Cell c : cs) {
                    if (c != null) {
                        c.reset();
                    }
                }
            }
        }
    
  • 相关阅读:
    转载-HTTP
    程序员如何写出杀手级的简历
    23 岁的你,曾处于什么样的状态?现在呢?
    IntelliJ IDEA 14 java项目中添加jar包
    BNR Android Demo学习笔记(一)——CrimeIntent
    Android高仿微信(一)——如何消除启动时的白屏
    Swift2.1 语法指南——高级操作符
    Swift2.1 语法指南——访问控制
    Swift2.1 语法指南——泛型
    Swift2.1 语法指南——协议
  • 原文地址:https://www.cnblogs.com/zhuxudong/p/10055460.html
Copyright © 2020-2023  润新知