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

ConcurrentHashMap的源码分析-fullAddCount源码分析相关推荐

  1. (五)Tomcat源码阅读:Connector组件分析

    一.概述 因为Connector组件没有实现接口规范,因此我们直接对该类的方法进行分析即可. 二.源码阅读 阅读思路,我的阅读思路是这样的,大的类无非就是对小类的使用,因此我们想分析整体的一下架构的化 ...

  2. 老李推荐:第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用 1...

    老李推荐:第5章5节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 获取系统服务引用 上一节我们描述了monkey的命令处理入口函数run是如何调用optionPro ...

  3. 手机自动化测试:Appium源码分析之跟踪代码分析四 1

    手机自动化测试:Appium源码分析之跟踪代码分析四 控制器模块 // Appium webserver controller methods // https://github.com/hugs/a ...

  4. 【原创】【专栏】《Linux设备驱动程序》--- LDD3源码目录结构和源码分析经典链接

    http://blog.csdn.net/geng823/article/details/37567557 [原创][专栏]<Linux设备驱动程序>--- LDD3源码目录结构和源码分析 ...

  5. 【Linux 内核】进程管理 ( 进程相关系统调用源码分析 | fork() 源码 | vfork() 源码 | clone() 源码 | _do_fork() 源码 | do_fork() 源码 )

    文章目录 一.fork 系统调用源码 二.vfork 系统调用源码 三.clone 系统调用源码 四._do_fork 函数源码 五.do_fork 函数源码 Linux 进程相关 " 系统 ...

  6. 【Android 热修复】热修复原理 ( 类加载分析 | 分析 PathClassLoader 源码 | 分析 BaseDexClassLoader 源码 | 分析 PathDexList 源码 )

    文章目录 一.分析 PathClassLoader 源码 二.分析 BaseDexClassLoader 源码 三.分析 PathDexList 源码 四. 源码资源 一.分析 PathClassLo ...

  7. 【Android 电量优化】JobScheduler 源码分析 ( JobServiceContext 源码分析 | 闭环操作总结 | 用户提交任务 | 广播接收者接受相关广播触发任务执行 )★

    文章目录 一.JobServiceContext 引入 二.JobServiceContext 源码分析 三.用户在应用层如何使用 JobScheduler 四.用户提交任务 五.广播接收者监听广播触 ...

  8. 老李推荐:第6章1节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览 1...

    老李推荐:第6章1节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览 在上一章中我们有简要的介绍了事件源是怎么一回事,但是并没有进行详细的描述.那么往下的这几个 ...

  9. kafka源码分析之一server启动分析

    0. 关键概念 关键概念 Concepts Function Topic 用于划分Message的逻辑概念,一个Topic可以分布在多个Broker上. Partition 是Kafka中横向扩展和一 ...

最新文章

  1. 详解PyTorch中的ModuleList和Sequential
  2. VScode快速一键生成html、vue、jsx、ajax、sass、docker等代码片段
  3. Ueditor配置及在项目中的使用
  4. iPhone应用程序图标 - 精确半径?
  5. 用devc++表白_教你用C语言加图形库打造炫酷表白连连看
  6. zcmu1734: 18岁
  7. 【Tensorflow】解决No module named ‘matplotlib‘/‘pandas‘
  8. c语言为什么有这么多的编程环境?_为什么98%的程序员学编程都会从C语言开始?...
  9. 华为鸿蒙beta版发布会,华为HarmonyOS手机体验鸿蒙版微博:仅9.1MB 附华为鸿蒙发布会直播入口...
  10. c语言健身房会员管理系统,健身房会员管理系统c#.net
  11. [渝粤教育] 中国地质大学 计算机组成原理 复习题 (2)
  12. python中capital是什么意思_Capital是什么意思?
  13. 如何下载Django 离线文档?
  14. 史上最强!PC时代的20位英雄(组图)
  15. 用技术入股解决互联网创业技术问题,这事儿靠谱吗?
  16. 4G 工业路由器并入cisco专网
  17. #ps –ef_ps命令 – 显示进程状态
  18. hive中NULL值问题
  19. 编写有效用例笔记- 第六章 前置条件、触发事件和保证
  20. 线段树节点个数的递推公式与通项公式

热门文章

  1. [No0000119]什么是柳比歇夫的时间事件记录法
  2. Oracle把逗号分割的字符串转换为可放入in的条件语句的字符数列
  3. 【转】Java 枚举7常见种用法
  4. zigbee 万能遥控器 裸机发送和协议栈发送
  5. 大话设计模式—策略模式
  6. 记录一次dubbo项目实战
  7. viewport,html,body在pc和移动的差异
  8. Zabbix 3.2.6 升级到 Zabbix 3.4.3
  9. $http中文乱码|param乱码|angular提交后台乱码|
  10. 各种版本的ST-LINK仿真器