欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-27 08:46:33
fullAddCount主要是用来初始化CounterCell,来记录元素个数,里面包含扩容,初始化等操作private final void fullAddCount(long x, boolean wasUncontended) {int h; //获取当前线程的probe的值,如果值为0,则初始化当前线程的probe的值,probe就是随机数 if ((h = ThreadLocalRandom.getProbe()) == 0) { ThreadLocalRandom.loc...

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

 

本文地址:https://blog.csdn.net/Leon_Jinhai_Sun/article/details/111997777