专栏首页回顾LongAccumulator介绍,使用,实现原理

LongAccumulator介绍,使用,实现原理

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使用
LongAdder longAdder = new LongAdder();

// LongAccumulator使用
LongAccumulator longAccumulator = new LongAccumulator(new LongBinaryOperator() {
    @Override
    public long applyAsLong(long left, long right) {
        return left + right;
    }
}, 0);

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

随后我们将目光转向到下面代码,从下面代码我们即可知道LongAccumulator相比于LongAdder的不同在于,在调用casBase时后者传递的是b+x,前者则使用了r=function.applyAsLong(b=base, x)来计算。

// LongAdder 的 add方法
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);
    }
}

// LongAccumulator 的 accumulate方法
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函数来计算。

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

总结

本节简单介绍了LongAccumulator的原理。LongAdder类时LongAccumulator的一个特例,只是后者提供了更强大的功能,让用户自定义累加规则。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • AQS(上) 同步队列AQS介绍篇

    AbstractQueuedSynchronizer抽象同步队列简称AQS,它是实现同步器的基础组件,并发包中锁的底层就是使用AQS实现的。另外,大多数开发者可...

    YanL
  • [Java 并发]读锁/写锁

    之前我们都知道在一个变量被读或者写数据的时候每次只有一个线程可以执行,那么今天我们来看一下读写锁,读写两不误ReadWriteLock。

    YanL
  • CountDownLatch

    定义初始化的时候,需要传入一个正数来初始化计数器**(0也可以,但这样定义没有实际意义)。有两个方法countDown()**用于递减计数器,await()方法...

    YanL
  • JDK8中新增原子性操作类LongAccumulator

    LongAdder类是LongAccumulator的一个特例,LongAccumulator提供了比LongAdder更强大的功能,如下构造函数其中accum...

    加多
  • Tcl中的数学运算

    Tcl中的数学运算,即便是很简单的两个数相加,都要用到命令expr,看下面这个例子。在这个例子中,计算x1与x2之和时通过expr命令实现。可以看到如果直接写{...

    Lauren的FPGA
  • FreeRTOS 任务调度 任务切换

    前面文章 < FreeRTOS 任务调度 任务创建 > 介绍了 FreeRTOS 中如何创建任务以及其具体实现。 一般来说, 我们会在程序开始先创建若干个任务...

    orientlu
  • 双指针法:总结篇!

    相信大家已经对双指针法很熟悉了,但是双指针法并不隶属于某一种数据结构,我们在讲解数组,链表,字符串都用到了双指针法,所有有必要针对双指针法做一个总结。

    代码随想录
  • LeetCode 653. 两数之和 IV - 输入 BST(二叉搜索树迭代器&双指针)

    给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。

    Michael阿明
  • 案例 | 为什么奢侈品牌纷纷押注微信小程序?

    微信推出小程序至今已接近两年,逐渐习惯数字化趋势的奢侈时尚品牌们从最初的观望到全面拥抱并没有耗费太多的时间。

    云蚁cloudant
  • 美团点评2020年测试工程师笔试题

    1.每年的5月17日,美团点评都会在全国各大城市举办517吃货节优惠活动,如果你来负责手机端517某一个活动的测试任务,你会想到从哪些方面测试,来保证517活动...

    ITester软件测试小栈

扫码关注云+社区

领取腾讯云代金券