1、複習
2、LongAdder源碼分析
1.繼承與實現關係
-
LongAdder類繼承自Striped64這個類,同時實現了Serializable接口
abtract class Strped64{
transient volatile Cell[] cells;
transient volatile long base;
transient volatile int cellsBusy;
........
}
-
繼承了三個變量,其中cells變量就是Cell實例數組,用於存放共享變量,base值是一個基礎值,cellsBusy用來實現自旋鎖,其值只有0和1
-
「當建立Cell元素,擴容Cell數組或者初始化Cell數組的時候,使用CAS操做該變量來保證同時只有一個線程能夠進行其中之一的操做。」
2.關鍵字transient
-
講這個關鍵字以前不得不提一下Seriable這個接口,咱們以LongAdder這裏類爲例,因爲它實現了序列化這個接口,也就意味着這個類能夠序列化,而且保存到磁盤中,而不單單是隻在內存中使用,而後對於有一些數據是不該該序列化的,好比密碼,關鍵信息等等,這些數據保存到變量以後,而後被transient這個關鍵字修飾,那麼未來序列化這個實例的時候,就不會保存這個變量,保證信息安全。
3.Cell源碼
package com.ruigege.AtomicOperationClass4;
import sun.misc.Unsafe;
@sun.misc.Contended public class LongAdderTest {
volatile long value;
public LongAdderTest(long value) {
this.value = value;
}
private static final Unsafe unsafe;
private static final long valueOffset;
static {
try {
unsafe = Unsafe.getUnsafe();
Class<?> ak = Cell.class;
valueOffset = unsafe.objectFieldOffset(ak.getDeclaredField("value"));
}catch(Exception e) {
throw new Error(e);
}
}
final long cas(long cmp,long val) {
return unsafe.compareAndSwapLong(this,valueOffset,cmp,val);
}
}
-
cas函數使用了CAS操做,保證了當前線程更新時被分配的Cell元素中的value值的原子性。
public long sum() {
Cell[] as = cells;
long sum = base;
if(as != null) {
for (int i=0;i<as.length;i++) {
if(as[i] != null) {
sum += as[i].value;
}
}
}
}
-
上面這個函數就是求總值,可是因爲沒有加鎖,因此在計算的過程當中,有可能Cell實例的值變化了,因此獲得的值可能不許。
public void reset() {
Cell[] as = cells;
base = 0L;
if(as != null) {
for (int i=0;i<as.length;i++) {
if(as[i] != null) {
as[i].value = 0L;
}
}
}
}
public long sunThenReset() {
Cell[] as = cells;
int sum = base;
if(as != null) {
for (int i=0;i<as.length;i++) {
if(as[i] != null) {
sum += as[i];
as[i] = 0L;
}
}
}
}
-
先求和,而後Cell數組置空,可是這個方法沒有加鎖,容易形成數據不一致。
public void add(long x) {
Cell[] as;
long b,v;
int m;
Cell a;
if((as = cells) != null) || !caseBase(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);
}
}
}
final boolean casBase(long cmp,long val) {
return UNSAFE.compareAndSwapLong(this,BASE,cmp,val);
}
final void longAccumulate(long x,LongBinaryOperator fn,boolean wasUncontended) {
int h;
if(h = getProbe() == 0) {
ThreadLocalRandom.current();
h = getProbe();
wasUncontended = true;
}
boolean collide = false;
for(;;) {
Cell[] as;Cell a;int n;long v;
if((as=cells) != null && (n=as.length)>0) {
if((a=as[(n-1) &h]) == null) {
if(cellsBusy == 0) {
Cell r = new Cell(x);
if(cellsBusy == 0 && casCellsBusy()) {
boolean created = false;
}
try {
Cell[] rs;int m,j;
if((rs=cells) != null && (m=rs.length)>0 && rs[j = (m-1) &h] == null) {
rs[j] = r;
created = true;
}
}finally {
cellsBusy = 0;
}
if(created) {
break;
}
continue;
}
}
collide = false;
}else if(!wasUntended) {
wasUncontended = true;
}else if(a.cas(v=a.value,((fn==null)?v+x : fn.applyAsLong(v,x)))) {
break;
}else if(n >= NCPU || cells != as) {
collide = false;
}else if(!collide) {
collide = ture;
}else if(cellsBusy == 0 && casCellsBusy()) {
try {
if(cells == as) {
Cell[] rs = new Cell[n<<1];
for(int i=0;i<n;++i) {
rs[i] = as[i];
}
cells = rs;
}
}finally {
cellsBusy = 0;
}
}
}
}
3、源碼:
-
所在包:com.ruigege.AtomicOperationClass4
-
https://github.com/ruigege66/ConcurrentJava
-
-
-
歡迎關注微信公衆號:傅里葉變換,我的帳號,僅用於技術交流