LongAccumulator
一个或多个变量通过提供的函数共同维护运行时长整型数值。当跨线程竞争更新时,变量集可能会动态增长来减少争用。方法(get或者等效地longValue),在维护的更新变量值中返回当前值。
当多个线程更新用于诸如收集统计信息之类的目的,而不是用于细粒度的同步控制的公共值时,此类通常比AtomiLong更可取。低竞争情况下,这两个类有相似的特征。但在竞争激烈的情况下,此类的预期吞吐量会大大提高,但要消耗更多的空间。
不能保证并且不能依赖于线程内或者线程间的叠加顺序,因此此类仅适用于叠加顺序无关紧要的函数。所供的累加功能应无副作用,因为当尝试更新由于线程间争用而失败时,可能会重新利用该累加器功能。应用该函数时,将当前值作为其第一个参数,并将给定的update值作为第二个参数。比如,要保持最大运行值,你应该提供Long::max以及Long.MIN_VALUE作为标识。
类LongAdder提供了这个类用于特殊维护累加值的函数用法。new LongAdder()的调用相当于LongAccumulator((x,y)->x+y,0L}
这个类继承于Number,但是没有定义诸如equals、hashCode、compareTo方法因为这些实例预期是可变的,所以作为集合的键值是无效的。
public void accumulate(long x){
Cell[]tempCells;
long tempBase,value,result;
int maxIndex;
Cell operateCell;
if((tempCells = cells)!=null ||
(result = function.applyAsLong(tempBase = base, x))! = b && !casBase(tempBase,result){
//数组不为空,或者数组为空,但是更新base值失败
boolean uncontended=true;
if(tempCells == null || (maxIndex = tempCells.length - 1)<0 || (operateCell = tempCells[getProbe() & length]) == null ||
!(uncontended = (result = function.applyAsLong(value = operateCell.value,x)) == value || operateCell.cas(value,result))){
//①数组为空 ②数组不为空,但是插槽值为空 ③ 插槽值也不为空,但是插槽值要更新的值与旧值不相同并且该插槽cas操作失败,就去striped64的方法中进行操作
longAccumulate(x,function,uncontended);
}
}
}
返回当前值。返回值不是原子快照,没有并发更新的情况下调用返回准确的结果,但是可能不会合并在计算值时发生的并发更新。(也就是并发时获取值可能不准确)
public long get(){
Cell[] resultCells = cells; Cell operateCell;
long result = base;
if(resultCells != null){
for(int i=0;i<resultCells.length; ++i){
if((operateCell = resultCells[i]) !=null)
result = function.applyAsLong(result,operateCell.value);
}
}
return result;
}
重置变量以保持对标识值的更新。这个方法可能是创建新更新程序的有效替代方法,但仅在没有并发更新时才有效。但是因为这个方法本质上是竞争的,所以仅当已知没有线程在同时更新时才应该使用此方法。
public void reset(){
Cell[] tempCells = cells;
Cell operateCell;
if(tempCells != null){
for(int i=0;i<tempCells.length; ++i){
if((operateCell = tempCells[i])!=null){
operateCell.value=identity;
}
}
}
}
等同于 get()之后再reset().此方法可能使用于多线程计算之间的静态点。如果与此方法同步更新,则返回值不能保证是重置之前发生的最终值。
public long getThenReset(){
Cell[] tempCells = cells;
long result = base;
Cell operateCell;
base = identity;
if(tempCells != null){
for(int i=0;i<tempCells.length; ++i){
if((operateCell = tempCells[i])!=null){
long value = operateCell.value;
operateCell.value = identity;
result = function.applyAsLong(result,value);
}
}
}
return result;
}
LongAdder与LongAccumulator的对应方法:
add(long x) ==> accumulate(long x)
sum() ==> get()
DoubleAccumulator与DoubleAdder与此类似。只是将Double使用Long保存,操作时将Long转回Double进行计算,最后再保存Long。
Double.doubleToRawLongBits()与Double.longBitsToDouble()进行Double与Long的互转。