Java系列-ConcurrentHashMap-addCount

1.addCount 

 

public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
    implements ConcurrentMap<K,V>, Serializable {

    private final void addCount(long x, int check) {
        CounterCell[] as; 
        long b, s;
        //1.counterCells不为null
        //2.或者 x加到baseCount失败
        if ((as = counterCells) != null ||
            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
            CounterCell a; 
            long v; 
            int m;
            boolean uncontended = true;

            //as为null
            //as长度小于1
            //as[ThreadLocalRandom.getProbe() & m]为null
            //as[ThreadLocalRandom.getProbe() & m].value+x失败
            if (as == null || (m = as.length - 1) < 0 ||
                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
                !(uncontended =
                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
                fullAddCount(x, uncontended);
                return;
            }
            //能走到这里,表明as不为null,as[ThreadLocalRandom.getProbe() & m].value+x成功
            if (check <= 1){
                return;
            }
            //计算个数
            s = sumCount();
        }
        if (check >= 0) {
            Node<K,V>[] tab, nt; 
            int n, sc;

            //1.s>=sc (数组元素个数大于或者等于扩容阈值)
            //2.table不为null
            //3.table的length小于MAXIMUM_CAPACITY
            while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
                   (n = tab.length) < MAXIMUM_CAPACITY) {
                int rs = resizeStamp(n);
                if (sc < 0) { //sc小于0,说明有线程正在扩容,那么会协助扩容
                     //扩容结束或者扩容线程数达到最大值或者扩容后的数组为null或者没有更多的桶 
                     //位需要转移,结束操作
                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                        transferIndex <= 0){
                        break;
                    }
                     //扩容线程加1,成功后,进行协助扩容操作
                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)){
                        transfer(tab, nt);
                    }
                } else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                             (rs << RESIZE_STAMP_SHIFT) + 2)){
                    //扩容
                    transfer(tab, null);
                }
                s = sumCount();
            }
        }
    }
}

2.fullAddCount 

初始化 counterCells,初始容量是2,将x放到要放入的位置;

如果没有冲突,放入该桶;

如果要放入的桶有冲突,重新生成hash,再看有没有冲突;

如果重新生成hash后,还是有冲突,将x增加到该桶的value;

如果有冲突,数组容量没有超过cpu核数,对数组进行扩容,新容量为老容量的2倍;

public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
    implements ConcurrentMap<K,V>, Serializable {

    private final void fullAddCount(long x, boolean wasUncontended) {
        int h;
        if ((h = ThreadLocalRandom.getProbe()) == 0) {//用来获得随机数
            ThreadLocalRandom.localInit();      // force initialization
            h = ThreadLocalRandom.getProbe();
            wasUncontended = true;
        }
        boolean collide = false;                // True if last slot nonempty
        for (;;) {
            CounterCell[] as; 
            CounterCell a; 
            int n; 
            long v;
            //数组不为空,优先对数组中CouterCell的value累加
            if ((as = counterCells) != null && (n = as.length) > 0) {
                if ((a = as[(n - 1) & h]) == null) {//应该放入的桶为null
                    if (cellsBusy == 0) {            // Try to attach new Cell
                        CounterCell r = new CounterCell(x); // Optimistic create
                        if (cellsBusy == 0 &&
                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                            boolean created = false;
                            try {               // Recheck under lock
                                CounterCell[] rs; 
                                int m, j;
                                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;           // Slot is now non-empty
                        }
                    }
                    collide = false;
                } else if (!wasUncontended){       // CAS already known to fail
                    wasUncontended = true;      // Continue after rehash
                } 
                //x添加到a.value
                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x)){
                    break;
                } else if (counterCells != as || n >= NCPU){ 
                    collide = false;            // At max size or stale
                } else if (!collide){ 
                    collide = true;
                } else if (cellsBusy == 0 &&
                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                    try {
                        if (counterCells == as) {// Expand table unless stale
                            //数组扩容
                            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;                   // Retry with expanded table
                }
                h = ThreadLocalRandom.advanceProbe(h);//重新计算hash
            } 
            //CounterCell数组为空,并且没有线程在创建数组,修改标记,并创建数组
            else if (cellsBusy == 0 && counterCells == as &&
                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                boolean init = false;
                try {                           // Initialize table
                    if (counterCells == as) {
                        //创建数组,容量为2
                        CounterCell[] rs = new CounterCell[2];
                        rs[h & 1] = new CounterCell(x);//这次的x保存至rs[h & 1]
                        counterCells = rs;
                        init = true;
                    }
                } finally {
                    cellsBusy = 0;
                }
                if (init){
                    break;
                }
            } 
            //数组为空,并且有别的线程在创建数组,那么尝试对baseCount做累加,
            //成功就退出循环,失败就继续循环
            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x)){
                break;                          // Fall back on using base
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/251766.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在Docker部署draw.io流程图软件并实现公网远程访问

前言 提到流程图&#xff0c;大家第一时间可能会想到Visio&#xff0c;不可否认&#xff0c;VIsio确实是功能强大&#xff0c;但是软件为收费&#xff0c;并且因为其功能强大&#xff0c;导致安装需要很多的系统内存&#xff0c;并且是不可跨平台使用。所以&#xff0c;今天给…

深入学习《大学计算机》系列之第1章 1.3节——计算机科学的知识领域

一.欢迎来到我的酒馆 第1章 1.3节&#xff0c;计算机科学的知识领域。 目录 一.欢迎来到我的酒馆二.计算机科学的知识领域1.什么是计算机科学 二.计算机科学的知识领域 什么是计算机科学&#xff1f;什么是计算机学科&#xff1f;计算机科学包含哪些知识领域&#xff1f; …

PyCharm控制台异常堆栈乱码问题解决

目录 1、问题描述2、问题原因3、问题解决 1、问题描述 PyCharm环境都已经配置成了UTF-8编码&#xff0c;控制台打印中文也不会出现乱码&#xff0c;但异常堆栈信息中如果有中文会出现中文乱码&#xff1a; 这种该怎么解决呢&#xff1f; 2、问题原因 未将PyCharm编码环境与项目…

接口自动化测试实操【设置断言思路】

1 断言设置思路 这里总结了我在项目中常用的5种断言方式&#xff0c;基本可能满足90%以上的断言场景&#xff0c;具体参见如下脑图&#xff1a; 在这里插入图片描述 下面分别解释一下图中的五种思路&#xff1a; 1&#xff09; 响应码 对于http类接口&#xff0c;有时开发人…

Python:Jupyter

Jupyter是一个开源的交互式计算环境&#xff0c;由Fernando Perez和Brian Granger于2014年创立。它提供了一种方便的方式来展示、共享和探索数据&#xff0c;并且可以与多种编程语言和数据格式进行交互。Jupyter的历史可以追溯到2001年&#xff0c;当时Fernando Perez正在使用P…

Linux Shell——输入输出重定向

输入输出重定向 1. 重定向输入2. 重定向输出 总结 最近学习了shell语法&#xff0c;总结一下关于输入输出重定向的知识。 一般情况下&#xff0c;linux每次执行命令其实都会打开三个文件&#xff0c;分别是&#xff1a; 标准输入stdin 文件描述符为0 标准输出stdout 文件描述符…

《软件方法(下)》8.2.3 提炼类和属性(1)

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 8.2 建模步骤C-1 识别类和属性 8.2.2 三种分析类 8.2.2.6 自测题 扫码或访问http://www.umlchina.com/book/quiz8_2_2.html完成在线测试&#xff0c;做到全对以获得答案。 1. [单选…

springMVC-@RequestMapping

基本介绍 RequestMapping注解可以指定控制器/处理器的某个方法的请求的url, 示例 &#xff08;结合springMVC基本原理理解&#xff09; Controller public class UserHandler {RequestMapping(value "/login")public String login() {System.out.println("登…

微服务保护--熔断降级

1.熔断降级介绍 熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例&#xff0c;如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求&#xff1b;而当服务恢复时&#xff0c;断路器会放行访问该服务的请求。 断路器控制熔断和放行…

ShuffleNet V1+V2(pytorch)

V1 V1根本思想&#xff1a; 1.GConv替换resnet的普通1*1Conv 2.GConv后加channel shuffle模块 对GConv的不同组进行重新组合。channel_shuffle a是resnet模块&#xff0c;b&#xff0c;c是ShuffleNetV1的block&#xff0c;在V1版中&#xff0c;两模块branch2的第一个1*1卷积…

linux日志管理_日志系统

10.1 日志系统&#xff08;系统日志管理&#xff09;syslog&rsyslog 日志&#xff1a;主要用途是系统审计、监测追踪和分析统计。 ​ Linux内核由很多子系统组成&#xff0c;包括网络、文件访问、内存管理等。子系统需要给用户传送一些消息&#xff0c;这些消息内容包括消…

2023/12/17 初始化

普通变量&#xff08;int,float,double变量&#xff09;初始化&#xff1a; int a0; float b(0); double c0; 数组初始化&#xff1a; int arr[10]{0}; 指针初始化&#xff1a; 空指针 int *pnullptr; 被一个同类型的变量的地址初始化&#xff08;赋值&#xff09; int…

Latex表格的问题(如何合并单元格、单元格垂直居中、水平居中)

用到的package % 表格里面合并单元格用到的 \usepackage{multirow} % 表格 \usepackage{tabularx} % 限制图片或者表格在文字下方 \usepackage{float} % y应该就是这两个包&#xff0c;如果报错就去搜索一下&#xff0c;可以找得到的怎么实现水平居中 \begin{table}[H] \cent…

【ZYNQ】AXI4总线接口协议学习

建议翻看着底部的参考文档资料和本文一起辅助阅读 本文带你详细的了解AXI总线协议&#xff0c;并且基于官方手册&#xff0c;能够提高你的手册阅读能力。 什么是AXI AXI 的英文全称是 Advanced eXtensible Interface&#xff0c;即高级可扩展接口&#xff0c;它是 ARM 公司所提…

QEMU源码全解析 —— virtio(13)

接前一篇文章&#xff1a; 通过前文书&#xff08;从QEMU源码全解析 —— virtio&#xff08;9&#xff09;开始&#xff09;对整个流程以及各个相关函数的解析&#xff0c;可以看到从virtio PCI代理设备的具现化到virtio设备的具现化过程。但前述分析还遗漏了一部分&#xff0…

一文了解Tomcat

文章目录 1、Tomcat介绍2、Tomcat使用配置2.1、Tomcat下载启动2.2、Tomcat启动乱码2.3、Tomcat端口号修改 3、Tomcat项目部署4、IDEA中使用Tomcat方式 1、Tomcat介绍 什么是Tomcat ​ Tomcat是Apache软件基金会一个核心项目&#xff0c;是一个开源免费的轻量级web服务器&#x…

【DataSophon】大数据管理平台DataSophon-1.2.1安装部署详细流程

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&am…

python绘制gif动图--避免收费拒绝水印

在cp源码解读-CSDN博客文章浏览阅读341次,点赞4次,收藏6次。coreutils:cp源代码分析https://blog.csdn.net/zhaiminlove/article/details/135026160中为了直观的表达文件是如何一步步的copy的,就想到了做一个gif,但是从来没弄过,一下有点麻爪了。 首先想到的是百度、Goog…

【算法刷题】Day18

文章目录 1. x 的平方根题干&#xff1a;算法原理&#xff1a;代码&#xff1a; 2. 搜索插入位置题干&#xff1a;算法原理&#xff1a;代码&#xff1a; 3. 珠宝的最高价值题干&#xff1a;算法原理&#xff1a;1. 状态表示2. 状态转移方程3. 初始化4. 填表顺序5. 返回值 代码…

LLM中的Prompt提示

简介 在LLM中&#xff0c;prompt&#xff08;提示&#xff09;是一个预先设定的条件&#xff0c;它可以限制模型自由发散&#xff0c;而是围绕提示内容进行展开。输入中添加prompt&#xff0c;可以强制模型关注特定的信息&#xff0c;从而提高模型在特定任务上的表现。 结构 …