美文网首页并发编程互联网科技程序员
JDK8中新增原子性操作类LongAccumulator

JDK8中新增原子性操作类LongAccumulator

作者: 阿里加多 | 来源:发表于2017-08-24 18:35 被阅读442次

    一、 LongAccumulator类原理探究

    LongAdder类是LongAccumulator的一个特例,LongAccumulator提供了比LongAdder更强大的功能,如下构造函数其中accumulatorFunction一个双目运算器接口,根据输入的两个参数返回一个计算值,identity则是LongAccumulator累加器的初始值。

        public LongAccumulator(LongBinaryOperator accumulatorFunction,
                               long identity) {
            this.function = accumulatorFunction;
            base = this.identity = identity;
        }
    
    public interface LongBinaryOperator {
    
           //根据两个参数计算返回一个值
           long applyAsLong(long left, long right);
    }
    

    LongAdder其实是LongAccumulator的一个特例,调用LongAdder相当使用下面的方式调用LongAccumulator。

    LongAdder adder = new LongAdder();
    
        LongAccumulator accumulator = new LongAccumulator(new LongBinaryOperator() {
            
            @Override
            public long applyAsLong(long left, long right) {
                return left + right;
            }
        }, 0);
    

    LongAccumulator相比于LongAdder可以提供累加器初始非0值,后者只能默认为0,另外前者还可以指定累加规则比如不是累加而是相乘,只需要构造LongAccumulator时候传入自定义双面运算器就OK,后者则内置累加的规则。

    从下面代码知道LongAccumulator相比于LongAdder不同在于casBase时候后者传递的是b+x,前者则是调用了r = function.applyAsLong(b = base, x)来计算。

    
        public void add(long x) {
            Cell[] as; long b, v; int m; Cell a;
            if ((as = cells) != null || !casBase(b = base, b + x)) {
                boolean uncontended = true;
                if (as == null || (m = as.length - 1) < 0 ||
                    (a = as[getProbe() & m]) == null ||
                    !(uncontended = a.cas(v = a.value, v + x)))
                    longAccumulate(x, null, uncontended);
            }
        }
        
        public void accumulate(long x) {
            Cell[] as; long b, v, r; int m; Cell a;
            if ((as = cells) != null ||
                (r = function.applyAsLong(b = base, x)) != b && !casBase(b, r)) {
                boolean uncontended = true;
                if (as == null || (m = as.length - 1) < 0 ||
                    (a = as[getProbe() & m]) == null ||
                    !(uncontended =
                      (r = function.applyAsLong(v = a.value, x)) == v ||
                      a.cas(v, r)))
                    longAccumulate(x, function, uncontended);
            }
        }
    

    另外前者调用longAccumulate时候传递到是function,而后者是null,从下面代码可知当fn为null时候就是使用v+x加法运算这时候就等价于LongAdder,fn不为null时候则使用传递的fn函数计算,如果fn为加法则等价于LongAdder;

      else if (casBase(v = base, ((fn == null) ? v + x :
                                            fn.applyAsLong(v, x))))
                    break;                          // Fall back on using base
    

    更详细的说明敬请期待 Java并发编程基础之并发包源码剖析 一书的出版

    相关文章

      网友评论

        本文标题:JDK8中新增原子性操作类LongAccumulator

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