轉載自?Jdk1.8 JUC源碼增量解析(2)-atomic-LongAdder和LongAccumulator
功能簡介:
- LongAdder是jdk1.8提供的累加器,基于Striped64實現。它常用于狀態采集、統計等場景。AtomicLong也可以用于這種場景,但在線程競爭激烈的情況下,LongAdder要比AtomicLong擁有更高的吞吐量,但會耗費更多的內存空間。
- LongAccumulator和LongAdder類似,也基于Striped64實現。但要比LongAdder更加靈活(要傳入一個函數接口),LongAdder相當于是LongAccumulator的一種特例。
源碼分析:public?class?LongAdder?extends?Striped64?implements?Serializable?{??????private?static?final?long?serialVersionUID?=?7249069246863182397L;??????????????public?LongAdder()?{??????}??LongAdder繼承了Striped64,本身沒有任何域。
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);??????}??}??? ? ? ?add方法邏輯很簡單,先嘗試將x累加到base上,失敗的話再看看能不能從cell表中找到cell,找到的話再嘗試將x累加到這個cell里面,還失敗的話就調用longAccumulate方法,這個方法上篇分析Striped64的時候分析過。?
?
????public?void?increment()?{??????add(1L);??}??????public?void?decrement()?{??????add(-1L);??}??? ? ? ?遞增和遞減方法,不需要解釋了。?
public?long?sum()?{??????Cell[]?as?=?cells;?Cell?a;??????long?sum?=?base;??????if?(as?!=?null)?{??????????for?(int?i?=?0;?i?<?as.length;?++i)?{??????????????if?((a?=?as[i])?!=?null)??????????????????sum?+=?a.value;??????????}??????}??????return?sum;??}??? ? ? ?sum方法就是獲取當前LongAdder值的總和,包括base和cells value兩部分。?
public?void?reset()?{??????Cell[]?as?=?cells;?Cell?a;??????base?=?0L;??????if?(as?!=?null)?{??????????for?(int?i?=?0;?i?<?as.length;?++i)?{??????????????if?((a?=?as[i])?!=?null)??????????????????a.value?=?0L;??????????}??????}??}??? ? ? ?重置方法,將base和cells value兩部分值都置為0。?
public?long?sumThenReset()?{??????Cell[]?as?=?cells;?Cell?a;??????long?sum?=?base;??????base?=?0L;??????if?(as?!=?null)?{??????????for?(int?i?=?0;?i?<?as.length;?++i)?{??????????????if?((a?=?as[i])?!=?null)?{??????????????????sum?+=?a.value;??????????????????a.value?=?0L;??????????????}??????????}??????}??????return?sum;??}??獲取總和后重置。
? ? ? ?LongAdder間接繼承了Number,看下相關的方法實現:
public?long?longValue()?{???????return?sum();???}?????public?int?intValue()?{???????return?(int)sum();???}?????public?float?floatValue()?{???????return?(float)sum();???}?????public?double?doubleValue()?{???????return?(double)sum();???}????
?
? ? ? ?LongAdder的序列化使用序列化代理模式:
private?static?class?SerializationProxy?implements?Serializable?{??????private?static?final?long?serialVersionUID?=?7249069246863182397L;????????private?final?long?value;??????SerializationProxy(LongAdder?a)?{??????????value?=?a.sum();??????}????????private?Object?readResolve()?{??????????LongAdder?a?=?new?LongAdder();??????????a.base?=?value;??????????return?a;??????}??}????private?Object?writeReplace()?{??????return?new?SerializationProxy(this);??}????private?void?readObject(java.io.ObjectInputStream?s)??????throws?java.io.InvalidObjectException?{??????throw?new?java.io.InvalidObjectException("Proxy?required");??}???
?
- 再看一下LongAccumulator類,先看結構:
public?class?LongAccumulator?extends?Striped64?implements?Serializable?{??????private?static?final?long?serialVersionUID?=?7249069246863182397L;??????private?final?LongBinaryOperator?function;??????private?final?long?identity;????????public?LongAccumulator(LongBinaryOperator?accumulatorFunction,?????????????????????????????long?identity)?{??????????this.function?=?accumulatorFunction;??????????base?=?this.identity?=?identity;??????}??LongAccumulator和LongAdder不同,內部有一個函數接口和一個初始值。
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);??????}??}??? ? ? ?和LongAdder的add方法一樣的邏輯。?
?
public?long?get()?{??????Cell[]?as?=?cells;?Cell?a;??????long?result?=?base;??????if?(as?!=?null)?{??????????for?(int?i?=?0;?i?<?as.length;?++i)?{??????????????if?((a?=?as[i])?!=?null)??????????????????result?=?function.applyAsLong(result,?a.value);??????????}??????}??????return?result;??}??? ? ? ?將內部所有的零散值通過函數算出一個最終值。?
?
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;??????????}??????}??}????public?long?getThenReset()?{??????Cell[]?as?=?cells;?Cell?a;??????long?result?=?base;??????base?=?identity;??????if?(as?!=?null)?{??????????for?(int?i?=?0;?i?<?as.length;?++i)?{??????????????if?((a?=?as[i])?!=?null)?{??????????????????long?v?=?a.value;??????????????????a.value?=?identity;??????????????????result?=?function.applyAsLong(result,?v);??????????????}??????????}??????}??????return?result;??}??注意這里和LongAdder不同,這里的重置會將base和cells value都重置成初始值-identity。其他的Number方法和序列化方式和LongAdder一樣。
? ? ? ?代碼解析完畢!?
?
?
? ? ? ?參見:Jdk1.8 JUC源碼增量解析(1)-atomic-Striped64
? ? ? ?參見:Jdk1.6 JUC源碼解析(1)-atomic-AtomicXXX
總結
以上是生活随笔為你收集整理的Jdk1.8 JUC源码增量解析(2)-atomic-LongAdder和LongAccumulator的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。