ConcurrentHashMap的源码分析-fullAddCount源码分析

fullAddCount主要是用来初始化CounterCell,来记录元素个数,里面包含扩容,初始化等操作

private final void fullAddCount(long x, boolean wasUncontended) {
	int h; 
	//获取当前线程的probe的值,如果值为0,则初始化当前线程的probe的值,probe就是随机数 
	if ((h = ThreadLocalRandom.getProbe()) == 0) { 
		ThreadLocalRandom.localInit(); // force initialization 
		h = ThreadLocalRandom.getProbe(); 
		wasUncontended = true; // 由于重新生成了probe,未冲突标志位设置为true 
	} 
	boolean collide = false; // True if last slot nonempty 
	for (;;) {//自旋 
		CounterCell[] as; CounterCell a; int n; long v; 
		// 说明counterCells已经被初始化过了,我们先跳过这个代码,先看初始化部分 
		if ((as = counterCells) != null && (n = as.length) > 0) { 
			if ((a = as[(n - 1) & h]) == null) {// 通过该值与当前线程probe求与,获得cells的下标元素,和hash 表获取索引是一样的 
			if (cellsBusy == 0) { // cellsBusy=0表示counterCells不在初始化或者扩容状态下 
				CounterCell r = new CounterCell(x); // 构造一个CounterCell的值,传入元素个数 
				if (cellsBusy == 0 &&// 通过cas设置cellsBusy标识,防止其他线程来对counterCells并发处理 
				U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) { 
					boolean created = false; 
					try { // Recheck under lock 
						CounterCell[] rs; int m, j; 
						// 将初始化的r对象的元素个数放在对应下标的位置 
						if ((rs = counterCells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) { 
							rs[j] = r; 
							created = true; 
						} 
					} finally {//恢复标志位 
						cellsBusy = 0; 
					} 
					if (created)//创建成功,退出循环 
					break; 
					continue;//说明指定cells下标位置的数据不为空,则进行下一次循环 
				} 
			} 
			collide = false; 
			} 
			//说明在addCount方法中cas失败了,并且获取probe的值不为空 
			else if (!wasUncontended) // CAS already known to fail 
			wasUncontended = true; //设置为未冲突标识,进入下一次自旋 
			//由于指定下标位置的cell值不为空,则直接通过cas进行原子累加,如果成功,则直接退出 
			else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))// 
			break; 
			//如果已经有其他线程建立了新的counterCells或者CounterCells大于CPU核心数(很巧妙,线程的并发数不会超过cpu核心数) 
			else if (counterCells != as || n >= NCPU) 
			collide = false; //设置当前线程的循环失败不进行扩容 
			else if (!collide)//恢复collide状态,标识下次循环会进行扩容 
			collide = true; 
			//进入这个步骤,说明CounterCell数组容量不够,线程竞争较大,所以先设置一个标识表示为正在扩容 
			else if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) { 
				try { 
					if (counterCells == as) {// Expand table unless stale 
					//扩容一倍 2变成4,这个扩容比较简单 
					CounterCell[] rs = new CounterCell[n << 1]; 
					for (int i = 0; i < n; ++i) 
					rs[i] = as[i]; 
					counterCells = rs; 
					} 
				} finally { 
					cellsBusy = 0;//恢复标识 
				} 
					collide = false; 
					continue;//继续下一次自旋 
			} 
			h = ThreadLocalRandom.advanceProbe(h);//更新随机数的值 
		} 

		初始化	CounterCells	数组
		//cellsBusy=0表示没有在做初始化,通过cas更新cellsbusy的值标注当前线程正在做初	始化操作 
		else if (cellsBusy == 0 && counterCells == as && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) { 
			boolean init = false; 
			try { // Initialize table 
				if (counterCells == as) { 
				CounterCell[] rs = new CounterCell[2]; //初始化容量为2 
				rs[h & 1] = new CounterCell(x);//将x也就是元素的个数放在指定的数组	下标位置 
				counterCells = rs;//赋值给counterCells 
				init = true;//设置初始化完成标识 
				} 
			} finally { 
				cellsBusy = 0;//恢复标识 
			} 
				if (init) 
				break; 
		} 
		//竞争激烈,其它线程占据cell 数组,直接累加在base变量中 
		else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x)) 
		break; // Fall back on using base 
	} 
} 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值