DoubleAccumulator源码解析

DoubleAccumulator源码解析

DoubleAccumulator类介绍

DoubleAccumulator也是JDK提供的基于Striped64实现的线程安全的double累加器。

类图

DoubleAccumulator类图

主要属性

1
2
private final DoubleBinaryOperator function;
private final long identity; // use long representation

function:二元函数

identity:其实就是LongAdder中的base,它是将double类型的初始值转为long保存。

主要方法

DoubleAccumulator(DoubleBinaryOperator, double)

1
2
3
4
5
6
7
8
9
10
11
/**
* Creates a new instance using the given accumulator function
* and identity element.
* @param accumulatorFunction a side-effect-free function of two arguments
* @param identity identity (initial value) for the accumulator function
*/
public DoubleAccumulator(DoubleBinaryOperator accumulatorFunction,
double identity) {
this.function = accumulatorFunction;
base = this.identity = Double.doubleToRawLongBits(identity);
}

初始化一个DoubleAccumulator对象,并将传入的double类型初始值转为long型存储。

accumulate(double)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Updates with the given value.
*
* @param x the value
*/
public void accumulate(double x) {
Cell[] as; long b, v, r; int m; Cell a;
// 如果cells数组不为null,说明存在竞态条件
// 或者,将base更换为当前function.applyDouble(base,x)失败
if ((as = cells) != null ||
(r = Double.doubleToRawLongBits
(function.applyAsDouble
(Double.longBitsToDouble(b = base), x))) != b && !casBase(b, r)) {
// 存在竞态条件设置为true
boolean uncontended = true;
// 如果当前cell数组为null或者为空,又或者function.apply(base,x)==base,case(base, function.apply(base,x))失败,调用父类的doubleAccumulate方法
if (as == null || (m = as.length - 1) < 0 ||
(a = as[getProbe() & m]) == null ||
!(uncontended =
(r = Double.doubleToRawLongBits
(function.applyAsDouble
(Double.longBitsToDouble(v = a.value), x))) == v ||
a.cas(v, r)))
doubleAccumulate(x, function, uncontended);
}
}

get()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Returns the current value. The returned value is <em>NOT</em>
* an atomic snapshot; invocation in the absence of concurrent
* updates returns an accurate result, but concurrent updates that
* occur while the value is being calculated might not be
* incorporated.
*
* @return the current value
*/
public double get() {
Cell[] as = cells; Cell a;
double result = Double.longBitsToDouble(base);
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
result = function.applyAsDouble
(result, Double.longBitsToDouble(a.value));
}
}
return result;
}

获取base和各个cell的值的累加和

reset()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Resets variables maintaining updates to the identity value.
* This method may be a useful alternative to creating a new
* updater, but is only effective if there are no concurrent
* updates. Because this method is intrinsically racy, it should
* only be used when it is known that no threads are concurrently
* updating.
*/
public void reset() {
Cell[] as = cells; Cell a;
base = identity;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
a.value = identity;
}
}
}

将base设置为初始值identity,并将各个cell的初始值也设置为identity

getThenReset()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Equivalent in effect to {@link #get} followed by {@link
* #reset}. This method may apply for example during quiescent
* points between multithreaded computations. If there are
* updates concurrent with this method, the returned value is
* <em>not</em> guaranteed to be the final value occurring before
* the reset.
*
* @return the value before reset
*/
public double getThenReset() {
Cell[] as = cells; Cell a;
double result = Double.longBitsToDouble(base);
base = identity;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null) {
double v = Double.longBitsToDouble(a.value);
a.value = identity;
result = function.applyAsDouble(result, v);
}
}
}
return result;
}

获取和然后重置

toString()

1
2
3
4
5
6
7
/**
* Returns the String representation of the current value.
* @return the String representation of the current value
*/
public String toString() {
return Double.toString(get());
}

返回当前和的String形式

doubleValue()

1
2
3
4
5
6
7
8
/**
* Equivalent to {@link #get}.
*
* @return the current value
*/
public double doubleValue() {
return get();
}

返回当期值

longValue()

1
2
3
4
5
6
7
/**
* Returns the {@linkplain #get current value} as a {@code long}
* after a narrowing primitive conversion.
*/
public long longValue() {
return (long)get();
}

将当前和转为long返回。注意精度丢失,是一个向下转型

intValue()

1
2
3
4
5
6
7
/**
* Returns the {@linkplain #get current value} as an {@code int}
* after a narrowing primitive conversion.
*/
public int intValue() {
return (int)get();
}

将当前和转为int返回。注意精度丢失,是一个向下转型。

floatValue()

1
2
3
4
5
6
7
/**
* Returns the {@linkplain #get current value} as a {@code float}
* after a narrowing primitive conversion.
*/
public float floatValue() {
return (float)get();
}

将当前和转为float返回。注意精度丢失,是一个向下转型。