AtomicLong與LongAdder的區別

AtomicLong的原理數組

  AtomicLong是經過依靠底層的CAS來保障原子性的更新數據,在要添加或者減小的時候,會使用死循環不斷地cas到特定的值,從而達到更新數據的目的。服務器

LongAdder的原理多線程

  LongAdder是在AtomicLong的基礎上將單點更新壓力分散到各個節點,在低併發的時候經過對八色的直接更新能夠很好的保障和AtomicLong的性能基本保持一致,而在高併發的時候經過分散提升了性能。缺點就是LongAdder在統計的時候若是有併發更新,可能致使統計的數據有偏差。併發

LongAdder繼承了Striped64類

public class LongAdder extends Striped64 implements Serializable
 
LongAdder繼承了Striped64類,來實現累加功能的,它是實現高併發累加的工具類; 
Striped64的設計核心思路就是經過內部的分散計算來避免競爭。 
Striped64內部包含一個base和一個Cell[] cells數組,又叫hash表。 
沒有競爭的狀況下,要累加的數經過cas累加到base上;若是有競爭的話,會將要累加的數累加到Cells數組中的某個cell元素裏面。因此整個Striped64的值爲sum=base+∑[0~n]cells。
Striped64內部三個重要的成員變量:
/**
* 存放Cell的hash表,大小爲2的冪。
*/
transient volatile Cell[] cells;
/**
* 基礎值,
* 1. 在沒有競爭時會更新這個值;
* 2. 在cells初始化的過程當中,cells處於不可用的狀態,這時候也會嘗試將經過cas操做值累加到base。
*/
transient volatile long base;
/**
* 自旋鎖,經過CAS操做加鎖,用於保護建立或者擴展Cell表。
*/
transient volatile int cellsBusy;
 

成員變量cells

cells數組是LongAdder高性能實現的必殺器: 
AtomicInteger只有一個value,全部線程累加都要經過cas競爭value這一個變量,高併發下線程爭用很是嚴重; 
而LongAdder則有兩個值用於累加,一個是base,它的做用相似於AtomicInteger裏面的value,在沒有競爭的狀況不會用到cells數組,它爲null,這時使用base作累加,有了競爭後cells數組就上場了,第一次初始化長度爲2,之後每次擴容都是變爲原來的兩倍,直到cells數組的長度大於等於當前服務器cpu的數量爲止就不在擴容(想下爲何到超過cpu數量的時候就再也不擴容);每一個線程會經過線程對cells[threadLocalRandomProbe%cells.length]位置的Cell對象中的value作累加,這樣至關於將線程綁定到了cells中的某個cell對象上;
 

成員變量cellsBusy

cellsBusy,它有兩個值0 或1,它的做用是當要修改cells數組時加鎖,防止多線程同時修改cells數組,0爲無鎖,1爲加鎖,加鎖的情況有三種 
1. cells數組初始化的時候; 
2. cells數組擴容的時候; 
3. 若是cells數組中某個元素爲null,給這個位置建立新的Cell對象的時候;

成員變量base

它有兩個做用: 
1. 在開始沒有競爭的狀況下,將累加值累加到base 
2. 在cells初始化的過程當中,cells不可用,這時會嘗試將值累加到base上;

Cell內部類

//爲提升性能,使用註解@sun.misc.Contended,用來避免僞共享,
@sun.misc.Contended static final class Cell {
//用來保存要累加的值
volatile long value;
Cell(long x) { value = x; }
//使用UNSAFE類的cas來更新value值
final boolean cas(long cmp, long val) {
return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
}
private static final sun.misc.Unsafe UNSAFE;
//value在Cell類中存儲位置的偏移量;
private static final long valueOffset;
//這個靜態方法用於獲取偏移量
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> ak = Cell.class;
valueOffset = UNSAFE.objectFieldOffset
(ak.getDeclaredField("value"));
} catch (Exception e) {
throw new Error(e);
}
}
}
 
這個類很簡單,final類型,內部有一個value值,使用cas來更新它的值;Cell類惟一須要注意的地方就是Cell類的註解@sun.misc.Contended。
相關文章
相關標籤/搜索