眾所周知彤蔽,LongAdder通過分段更新的方式梢褐,保證了在高并發(fā)下依然性能很好。Long值在其內(nèi)部是分段保存的医寿,只有在真正獲取Longadder的值的時(shí)候才會(huì)去計(jì)算栏赴。
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;
}
在我的使用過程中,經(jīng)常會(huì)碰到的場景是靖秩,對LongAdder寫操作的并發(fā)很高须眷,但是對值的讀并發(fā)同樣很高竖瘾,這時(shí)候,每次獲取值都要調(diào)用sum()去實(shí)時(shí)計(jì)算就會(huì)顯得比較累贅花颗,影響性能捕传。所以在這個(gè)實(shí)現(xiàn)已經(jīng)很完美的類上,做了一個(gè)小小的優(yōu)化捎稚,思路很簡單乐横,緩存上次計(jì)算的long值,除非有寫操作今野,否則直接讀取緩存的值即可葡公。
具體見代碼&注釋
public class CacheLongAdder extends LongAdder implements Serializable {
private static final long serialVersionUID = 7249069246863181097L;
/**
* 上次寫時(shí)間
*/
private volatile Long lastModify = null;
/**
* 上次讀時(shí)間
*/
private volatile Long lastRead = null;
/**
* 緩存的long值
*/
private Long cacheValue = null;
public CacheLongAdder() {
this.lastModify = System.currentTimeMillis();
}
@Override
public void add(long x) {
super.add(x);
// 不需要對此值的變更進(jìn)行并發(fā)控制,判斷緩存值失效只需要比較大小即可
lastModify = System.currentTimeMillis();
}
@Override
public long sum() {
if (cacheValue == null || lastRead == null || lastRead < lastModify) {
cacheValue = super.sum();
// 在沒有寫操作的情況下条霜,直接使用緩存long值即可
// 只有在緩存失效催什,即發(fā)生了新的寫操作的情況下,才需要更新lastRead的時(shí)間宰睡,避免下次讀操作的判斷錯(cuò)誤
// 對并發(fā)情況下可能存在的誤差是可以容忍度的蒲凶,因?yàn)長ongAdder本身的sum方法就不是原子性的
lastRead = System.currentTimeMillis();
}
return cacheValue;
}
}