LongAdder源码分析

2 篇文章 0 订阅
1 篇文章 0 订阅

目录

1.Striped64

1.probe

2.NCPU

3.cells

4.base

5.cellsBusy

2.sum()

3.add()

4.longAccumulate()

5.reset()


1.Striped64

1.probe

获取当前线程在内存中的PROBE值,类似于线程的哈希值

static final int getProbe() {
	return UNSAFE.getInt(Thread.currentThread(), PROBE);
}

public static ThreadLocalRandom current() {
	if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0)
		localInit();
	return instance;
}


static final void localInit() {
	int p = probeGenerator.addAndGet(PROBE_INCREMENT);
	int probe = (p == 0) ? 1 : p; // probe值不能为0
	long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
	Thread t = Thread.currentThread();
	UNSAFE.putLong(t, SEED, seed);
	UNSAFE.putInt(t, PROBE, probe);
}
static final int advanceProbe(int probe) {
	probe ^= probe << 13;   
	probe ^= probe >>> 17;
	probe ^= probe << 5;
	UNSAFE.putInt(Thread.currentThread(), PROBE, probe);
	return probe;
}

2.NCPU

CPU的核心数,Cells数组的最大长度为大于等于NCPU的最小的2的N次方,比如NCPU为7,则Cells数组最大length为8

static final int NCPU = Runtime.getRuntime().availableProcessors();

3.cells

cell数组,长度永远为2的N次方,初始化后数组容量是2

transient volatile Cell @Nullable [] cells;

4.base

当不存在并发修改时直接CAS更新base值,当CAS修改base失败且cell数组初始化并发竞争时,继续CAS修改一次Base值作为fallback操作

transient volatile long base;

5.cellsBusy

标志底层数组是不是busy状态,busy为1、不busy为0

transient volatile int cellsBusy;

2.sum()

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;
}

3.add()

  • cells为null,尝试CAS修改base成功,直接返回

  • cells为null、尝试CAS修改base失败,或者cells不为null,都是直接进入if代码块

    • 如果cells已经完成了初始化,尝试寻址然后CAS修改值,成功后直接返回

    • 如果cells已经完成了初始化、且寻址后CAS修改值失败,代表存在竞争,uncontended为false

    • 如果cells还没完成了初始化,通过longAccumulate方法进行初始化

public void add(long x) {
	Cell[] as; long b, v; int m; Cell a;
    // cells为null 尝试CAS修改base 成功后返回
	if ((as = cells) != null || !casBase(b = base, b + x)) {
        // cells不为null 或者CAS修改base失败 进入IF代码块
		boolean uncontended = true;
		if (as == null || (m = as.length - 1) < 0 ||
			(a = as[getProbe() & m]) == null || // 获取当前线程哈希值在Cells上寻址slot
            // 若as不为null 且slot上不为null 尝试修改slot上的值
            // 若修改失败说明存在并发竞争 uncontended为false
			!(uncontended = a.cas(v = a.value, v + x))) 
            	// 核心方法
				longAccumulate(x, null, uncontended);
	}
}

4.longAccumulate()

  • 初始化PROBE

  • cells已经完成了初始化

    • cells是空闲状态、且CAS修改状态成功

      • recheck检查成功后,寻址后进行目标Cell对象值修改

      • recheck失败后,直接进行下一次循环

    • cells是忙碌状态,如果目前Cell上存在竞争,将wasUncontended由false改为ture

    • cells是忙碌状态,目标Cell上不存在并发竞争,继续尝试CAS修改目标Cell对象值,成功后直接返回

    • cells是忙碌状态,但尝试CAS修改目标Cell对象值失败,判断cells数组有没有扩容到最大容量或者有没有在进行扩容

      • 如果扩容到最大容量了、或者正在进行扩容,修改collide为false

    • cells是忙碌状态,且collide为false,修改collide为true,准备进行数组扩容

    • 如果这个时候cells是空闲状态、且CAS修改状态成功

      • recheck检查成功后,进行cells数组扩容,容量变为之前2倍

      • recheck失败后,直接进行下一次循环

    • 上面的判断完成后,使用新的散列方法,重新计算一个PROBE值

  • cells还没初始化,准备开始初始化

    • 初始容量是2

  • cells正在初始化过程中,fallback机制再去尝试CAS修改base值

    • 修改成功后直接返回

    • CAS修改base值失败后,继续下一次循环

final void longAccumulate(long x, LongBinaryOperator fn,
						  boolean wasUncontended) {
	int h;
    // 初始化PROBE值
	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) { // Cells数组已经完成了初始化
			if ((a = as[(n - 1) & h]) == null) {
				if (cellsBusy == 0) {       // cells数组是空闲状态 CAS修改成功后将新建的Cell对象放在cell处
					Cell r = new Cell(x);  
					if (cellsBusy == 0 && casCellsBusy()) { 
						boolean created = false;
						try {               
							Cell[] rs; int m, j; // rs是cells的引用
							if ((rs = cells) != null && // reCheck
								(m = rs.length) > 0 &&
								rs[j = (m - 1) & h] == null) {
									rs[j] = r;
									created = true;
							}
						} finally {
							cellsBusy = 0;
						}
						if (created) // 创建成功就跳出自旋
							break;
                        
						continue;  // 可能在reCheck的时候由于并发竞争失败了 继续下次循环
					}
				}
				collide = false; // 未哈希碰撞
			}
            
            // cells数组是busy状态 wasUncontended为false 
            // 这个时候修改wasUncontended为true 然后进行下面的else-if判断
			else if (!wasUncontended)      
				wasUncontended = true;
            
            // cells数组是busy状态、wasUncontended为true 继续尝试CAS修改cell上的Cell对象值
            // 修改成功结束自旋 否则继续下面的else-if判断
			else if (a.cas(v = a.value, ((fn == null) ? v + x :
										 fn.applyAsLong(v, x))))
				break;
            
            // cells数组是busy状态、wasUncontended为true、尝试CAS修改cell上的Cell失败
            // 如果这个时候cells数组已经扩容到了最大值 或者正在进行扩容 则哈希碰撞标志为false 继续下面else-if判断
			else if (n >= NCPU || cells != as)
				collide = false;    
            
            // cells数组是busy状态、wasUncontended为true、尝试CAS修改cell上的Cell失败
            // 且cells没有进行扩容操作、或者还没扩容到最大 这个时候修改哈希碰撞标志为true
			else if (!collide)
				collide = true;
            
            // collide为true、cells数组是空闲状态、且CAS修改为busy状态成功 接着开始cells数组的扩容操作
			else if (cellsBusy == 0 && casCellsBusy()) {
				try {
					if (cells == as) {      // reCheck 
						Cell[] rs = new Cell[n << 1];
						for (int i = 0; i < n; ++i)
							rs[i] = as[i];
						cells = rs;
					}
				} finally {
					cellsBusy = 0;
				}
				collide = false; // 扩容完成后 修改collide为false 
				continue;  // reCheck失败 继续下一次循环                 
			}
            
            // 上面一大坨if代码后 用新的散列函数计算一个新的PROBE值
			h = advanceProbe(h); 
		}
        
		else if (cellsBusy == 0 && cells == as && casCellsBusy()) { // cells数组没完成初始化 且是空闲状态
			boolean init = false;
			try {                          
				if (cells == as) {
					Cell[] rs = new Cell[2]; // 初始容量为2 
					rs[h & 1] = new Cell(x); 
					cells = rs;
					init = true;
				}
			} finally {
				cellsBusy = 0; // 初始化完毕 修改busy状态
			}
			if (init)
				break;
		}
        
        // cells数组正在由其他线程初始化、但是还没完成初始化 这里是一个fallback机制 再次尝试CAS修改base值
		else if (casBase(v = base, ((fn == null) ? v + x :     
									fn.applyAsLong(v, x))))
			break;                          
	}
}

5.reset()

public void reset() {
  internalReset(0L);
}
final void internalReset(long initialValue) {
   Cell[] as = cells;
   base = initialValue; // 修改base值
   if (as != null) {
       int n = as.length;
       for (int i = 0; i < n; ++i) { // 修改cells数组值
           Cell a = as[i]; 
           if (a != null) a.value = initialValue;
       }
   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值