1)LongAccumulator 的逻辑和 LongAdder 基本类似,唯一不同的是 LongAccumulator
持有一个函数式接口,目标值是通过该接口计算得到的,相对于 LongAdder,LongAccumulator 更灵活。
1)多线程并发更新一个统计值时可以采用 LongAccumulator,如最高同时在线人数。
1)LongAccumulator 使用空间换时间的模式会消耗更多的内存
/**
* 二元函数式接口
*/
private final LongBinaryOperator function;
/**
* 身份值
*/
private final long identity;
/**
* 基于一个二元函数式接口和身份值创建 LongAccumulator 实例
*/
public LongAccumulator(LongBinaryOperator accumulatorFunction,
long identity) {
function = accumulatorFunction;
base = this.identity = identity;
}
/**
* 使用指定的值 x 更新 LongAccumulator
*/
public void accumulate(long x) {
Cell[] cs; long b, v, r; int m; Cell c;
/**
* 1)cells 为 null &&
* 使用函数式接口基于 base 和目标值 x 计算新值不等于 b &&
* 尝试原子更新 base
* 2)cells 不为 null
*/
if ((cs = cells) != null
|| (r = function.applyAsLong(b = base, x)) != b
&& !casBase(b, r)) {
/**
* 1)原子更新失败
* 2)cells 不为 null
*/
boolean uncontended = true;
/**
* 1)cells 为 null,则执行初始化
* 2)通过线程探测值定位的 cell 为 null,则尝试直接写入值
* 3)基于 cell 值和目标值 x 计算后的值和旧值不相等 && 原子更新失败,
* 说明出现 cell 竞争,则需要重新计算并写入值。
*/
if (cs == null
|| (m = cs.length - 1) < 0
|| (c = cs[Striped64.getProbe() & m]) == null
|| !(uncontended =
(r = function.applyAsLong(v = c.value, x)) == v
|| c.cas(v, r))) {
longAccumulate(x, function, uncontended);
}
}
}
/**
* 根据函数式接口循环计算新值【参数为累计值和当前 Cell 中的旧值】并返回最终值,
* 如果计算过程中未发生竞争,则该值是精确的。
*/
public long get() {
final Cell[] cs = cells;
long result = base;
if (cs != null) {
for (final Cell c : cs) {
if (c != null) {
result = function.applyAsLong(result, c.value);
}
}
}
return result;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章