细说ConcurrentHashMap计数规则

ConCurrentHashMap并发环境时,如何计数的?—— sumCount()、fullAddCount() ConCurrentHashMap 在并发环境下的计数问题。主要有两个手段。针对源码,本文进行详细的说明 阅读详情

对于ConcurrentHashMap而言,需要保证的是任何操作的线程安全,包括对集合元素个数的统计。

一般在多线程下要统计一个全局数量大小,可以通过cas+循环(或者直接用Atomic相关的类)的方式实现,但是ConcurrentHashMap作者却并不是这样实现的。

先看看如何获取集合中的元素个数,通过调用size()方法:

public int size() {
    long n = sumCount();
    return ((n < 0L) ? 0 :
            (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
            (int)n);
}

ConcurrentHashMap获取整个集合的元素个数利用的是sumCount()方法来进行计算,在普通的HashMap中就是直接返回一个全局的size值。

final long sumCount() {
    CounterCell[] as = counterCells; CounterCell a;
    long sum = baseCount;
    if (as != null) {
        for (int i = 0; i < as.length; ++i) {
            if ((a = as[i]) != null)
                sum += a.value;
        }
    }
    return sum;
}

从sumCount方法中可以看出,结果总数来源于两部分,第一部分:全局baseCount变量值,这个值作用和size是差不多的;第二部分:CounterCell数组中的各个value。

ConcurrentHashMap的作者希望通过CounterCell数组来减少多线程环境下cas自旋所造成的损耗。(这个想法真的可以好好学习下🤔)

其实,CounterCell对象内部就只有一个用volatile修饰的value。

@sun.misc.Contended static final class CounterCell {
    volatile long value;
    CounterCell(long x) { value = x; }
}

接下去就深入看下ConcurrentHashMap是如何来实现计数的了。。。。

**addCount()**方法会在调用put()之类的方法后,如果是新增了节点就会执行该方法,x一般都是1。

private final void addCount(long x, int check) {
    CounterCell[] as; long b, s;
    // 当计数盒子为空的时候,直接修改baseCount
  	// 如果修改baseCount失败,将值保存到计数盒子
    if ((as = counterCells) != null ||
        !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
        CounterCell a; long v; int m;
      	// cas操作是否成功,默认true
        boolean uncontended = true;
      	// 如果计数盒子不为空,修改计数盒子中的值
      	// 如果计数盒子为null或者修改计数盒子值失败,
        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;
        }
        if (check <= 1)
            return;
        s = sumCount();
    }
    if (check >= 0) {
        Node<K,V>[] tab, nt; int n, sc;
        while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
               (n = tab.length) < MAXIMUM_CAPACITY) {
            int rs = resizeStamp(n);
            if (sc < 0) {
                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                    sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                    transferIndex <= 0)
                    break;
                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();
        }
    }
}

addCount优先是修改counterCells中的值,当counterCells还未初始化或者后续修改counterCells中的值失败了,才会尝试通过cas操作修改全局BASECOUNT的值。

其中,counterCells的初始化、扩容以及存在竞争时对counterCells中的值cas修改失败都是通过**fullAddCount(x, uncontended)**方法进行处理。

fullAddCount具体实现如下(核心大作);

// wasUncontended代表上一次执行cas往cell中增加值是否成功,不执行也为true
private final void fullAddCount(long x, boolean wasUncontended) {
    int h;
  	// 如果当前线程获取到的hash值为0,初始化ThreadLocalRandom并获取新的hash,最后将cas状态标志位恢复为true
    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;
        if ((as = counterCells) != null && (n = as.length) > 0) {
          	// 对应计数下标处CounterCell对象不存在
            if ((a = as[(n - 1) & h]) == null) {
                if (cellsBusy == 0) {            // Try to attach new Cell
                    CounterCell r = new CounterCell(x); // Optimistic create
                  	// 初始化前先将cellsBusy置为1
                    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
                    }
                }
              	// 其他线程在进行CounterCell数组修改操作,
                collide = false;
            }
          	// 当wasUncontended为false,代表之前的cas操作失败了,需要先重新计算下标值
            else if (!wasUncontended)       // CAS already known to fail
                wasUncontended = true;      // Continue after rehash
            // 1. 之前对象为null,其他线程初始化后进行cas操作
            // 2. 之前cas执行失败, 重新计算下标指后进行cas操作
            else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
                break;
          	// 如果counterCells被其他线程修改了 或者 数组长度大于等于CPU数 就不进行扩容
            else if (counterCells != as || n >= NCPU)
                collide = false;            // At max size or stale
          	// 将扩容标志位置为true,如果下次重新计算下标值后的cas操作还是失败了就进行扩容
            else if (!collide)
                collide = true;
          	// 如果当前循环中连续对CounterCell数组不为null(也可以一开始为null,但是进行初始化发现其他线程已经进行了初始化)的对象进行cas操作失败就进行扩容
            else if (cellsBusy == 0 &&
                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                try {
                  	// 将counterCells数组长度扩大一倍(保持2的幂)
                    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
            }
          	// 可能重新计算的场景:
          	//      1. 上一次cas操作执行失败
          	//      2. counterCells中途被其他线程修改了 或者 数组长度大于等于CPU数
          	//      3. 打算扩容前再获取一次新的hash
            h = ThreadLocalRandom.advanceProbe(h);
        }
        // 为原数组空间进行初始化
        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];
                    rs[h & 1] = new CounterCell(x);
                    counterCells = rs;
                    init = true;
                }
            } finally {
                cellsBusy = 0;
            }
            if (init)
                break;
        }
      	// 如果前面都失败了,最后再进行一次cas修改BASECOUNT的值
        else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
            break;                          // Fall back on using base
    }
}

标志变量

  • cellsBusy :表示是否可以进行counterCells对象的修改操作;

    ​ 1 —— counterCells正在初始化(包括整个数组的初始化以及数组元素CounterCell对象的初始化)

    0 —— 无初始化,可进行初始化

  • wasUncontended :

    ​ true —— 默认,代表不存在cas操作失败

    ​ false —— 调用fullAddCount之前的cas操作执行失败

  • collide : 扩容标志

    ​ true —— 可以扩容

    ​ false —— 不可以扩容

如何确定要往counterCells哪个下标处进行+1操作的?

​ counterCells数组的设计理念和用来存储Map中元素的数组是一样的。首先,数组的长度一定是2的次方(counterCells起始大小是2);其次,计算下表是利用某个值和数组长度减一进行&操作求得。在HashMap中这个值就是hashcode,而在ConcurrentHashMap中是ThreadLocalRandom中的Probe。一般情况下,该值对应不同的线程都是不同的,同一个线程获取到的也同时相同的值,这样可以保证一个线程都是对同一个counterCells数组中的对象进行计数操作,提高cas操作的成功率。

总结:

​ ConcurrentHashMap计数思路是通过引入一个类似HashMap中用来存储节点的数组,利用数组来减少多线程对同一变量写操作的竞争。ConcurrentHashMap利用和线程绑定的Probe的值来快速计算对应的数组下标,如果下标处对象为null,通过了乐观锁+双重检查的形式对对象或者整个数组进行初始化。一般线程会对应counterCells中的某个数组下标对象进行累加,如果不存在别的线程的竞争,cas往往都会执行成功。当别的线程计算出的下标值是同一个,就存在对counterCells中的对象的竞争,此时,执行cas操作失败的线程会重新计算一个新的下标然后继续累加,如果还是存在竞争,继续更换下标,当多次失败的话,ConcurrentHashMap就认为当前数组中的大部分对象都有对应的线程在执行,会对整个数组进行扩容,原数组下标处的对象不变(可以认为counterCells中的对象往往只有一个线程对应,如果有多个线程,各个线程的cas操作也能高效的执行,否则,其中部分线程就会更换数组下标)。

ConcurrentHashMap线程安全的实现原理 一、介绍 1.概念 ConcurrentHashMap是HashMap的线程安全版本,相对 HashMap 和 Hashtable, ConcurrentHashMap 增加了 Segment 层,每个 Segment 原理上等同于一个 Hashtable, ConcurrentHashMap 为 Segment 的数组。 向 ConcurrentHashMap 中插入数据或者读取数据,首先都要讲... 阅读详情

相关推荐

ConcurrentHashMap 原理与高并发实战:从分段锁到CAS锁桶

ConcurrentHashMap 是 Java 并发编程中支撑高吞吐 Map 操作的核心数据结构,其本质是通过细粒度锁机制(如分段锁、CAS + synchronized 锁单桶)在保证线程安全的前提下极大提升并发读写性能。它基于 volatile 可见性、无锁读设计、协作式扩容等底层原理,实现了远超 Hashtable 和 SynchronizedMap 的吞吐能力。技术价值在于平衡一致性与性能,适用于缓存计数、会话管理、实时指标聚合等典型高并发场景。本文深入剖析 JDK 1.5 至 1.9 的演进逻辑

weixin_33884611的博客 378

ConcurrentHashMap

ConcurrentHashMap:数组加链表,ConcurrentHashMap 包含一个Segment数组,而Segment是ConcurrentHashMap的内部类,在Segment中柏含一个HashEntry的数组,而HashEntry是ConcurrentHashMap的内部类,HashEntry中包含key和value以及next指针,所以HashEntry可以构成一个链表,通俗的讲...

qq_30035749的博客 228

PX4二次开发实战:从零构建自定义飞控模块

本文详细介绍了PX4二次开发的实战指南,从环境搭建到自定义飞控模块的创建,涵盖了uORB消息定义、外部传感器驱动集成、控制算法实现等关键步骤。通过具体代码示例和调试技巧,帮助开发者快速入门PX4二次开发,构建高效稳定的无人机飞控系统。

weixin_29175469的博客 339

Map 综述(三):彻头彻尾理解 ConcurrentHashMap

ConcurrentHashMap是J.U.C的重要成员,它是HashMap的一个线程安全的版本。在默认理想状态下,ConcurrentHashMap可以支持16个线程执行并发写操作及任意数量线程的读操作。本文将结合Java内存模型和JDK源代码,剖析其高并发的具体实现机制,包括在JDK中的定义和结构、并发存取、重哈希和跨段操作,并着重剖析了ConcurrentHashMap读操作不需要加锁的内在奥秘和原理。

Rico's Blogs 14万+

PCI-Express、MiniPCIe、ExpressCard接口转换说明/引脚互换关系

通过引脚PIN互换可以在PCI-Express、MiniPCIe、ExpressCard之间切换不同的接口;提供接口引脚表和标准尺寸图。

tech34的博客 7125

缺陷检测-金属表面缺陷检测

1介绍 缺陷检测是工业视觉技术中最重要的组成部分。业务广泛,场景丰富,技术难点高、工作量大。针对不同的场景,选择不同的相机和

huneng1991的专栏 5250

ConcurrentHashMap 的工作原理及源码分析,如何统计所有的元素个数

1.ConcurrentHashMap(线程安全): ConcurrentHashMap采用了非常精妙的"分段锁"策略,ConcurrentHashMap的主干是个Segment数组。 final Segment<K,V>[] segments; Segment继承了ReentrantLock(参照:https://blog.youkuaiyun.com/striveb/article/...

striveb的博客 4119

在win10系统上安装opnet14.5注意事项和步聚

opnet 14.5安装避坑!

miracle_eicont的专栏 1038

ConcurrentHashMap源码分析之计数:addCount、fullAddCount、size

ConcurrentHashMap(以下简称CHM)的计数比较有特色,跟很多实现不同的是,CHM并没有一个专门的属性数据,在实现上也没有用锁来同步。那么它到底是怎么实现的呢? CHM计数的总体原理 CHM在实现计数时,主要借助的是baseCount和counterCells(数组)两个属性。 baseCount是原生类型long,默认值0L baseCount在首次添加元素的时候设置为1 视并发情况的不同,可能在addCount中赋值,也可能在fullAddCount中赋值,且仅赋值一次 counterC

大数据时代的狂欢 1093

FPGA,关于安装使用libero IDE V9.2 及其gold floating license配置

3、license安装根据,下面的提示进行,跟随setting up the license server on a host教程操作。1、从官网下载Libero IDE v9.2(如下图中的Libero IDE v9.2 software)4、下载完成license解压包后还需要下载 Daemons license ,地址如下。(2)第一行并不是在内填写,而是直接用您电脑名替换掉(1)修改license.bat前四行是,其务必保持和案例位置相同(避免出错)............

JasonK的博客 4298

BAT007:批量为当前目录下的文件夹添加前缀或后缀

摘要:编写批处理程序,实现批量为当前目录下的文件夹添加前缀或后缀。

qq_31762031的博客 4052

ConcurrentHashMap 如何保证线程安全的?

常见面试问题Concurrent

m0_74037817的博客 1785

海上通信技术发展与研究综述

通过对海浪模型、节点运动特性、天线辐射特性等进行特征深度学习,考虑改变有效链路的持续时间、业务类型和容量的区别,以及卫星和节点的仰角等,改变通信策略,设计动态波束成形算法,优化折中浮标天线增益和波束宽度,适应海上环境,尤其是海浪运动时变的特性。目前的海上通信系统,同时包括海上无线通信系统、卫星通信系统、岸基通信系统、船载基站通信系统、空中基站通信系统等不同方法组成的通信系统来满足不同的需求,如海上无线通信系统通信成本低廉、卫星通信系统具有广域的覆盖范围、岸基通信网络可以实现数据高速传输。

weixin_70923796的博客 1001

ConcurrentHashMap介绍

有冲突时,将计数分散到不同的CounterCell中,减少竞争。该工具方法是对普通Map的包装,底层同样使用synchronized锁,锁对象为整个Map实例,本质和Hashtable一致,锁粒度粗,并发性能低下,不适合高并发业务场景。采用分段锁设计,线程操作数据时,先通过哈希定位到对应的Segment,仅对当前Segment加锁,其他Segment不受影响,可被其他线程并发访问。,只要有一个线程执行读写操作,整个Map都会被锁定,其他线程必须阻塞等待,多线程下完全串行执行,并发能力几乎为零。

2401_88060344的博客 358

数据分享|2023年OSM道路数据(全国,分省,分市)

首先这个工作非常有必要的,因为我们正常使用的道路的分类都是基于包括城市快速路、城市主干路、城市次干路这个体系的,大家对于这个分类体系应该更熟悉,但是OSM地图的道路分类又不是完全按这个来的,所以非常有必要重新分类;搞清楚道路类型是我们使用道路数据做很多工作的基础,比如我们在使用道路数据的时候,经常需要预估道路的行车速度,而这个速度一般就是根据道路类型来的,比如高架路的车速肯定就比城市支路快很多!下载分为两种情况,第一种是下载小区域的数据,比如下载一个街区的数据,第二种为下载整个中国范围的。

JData_Engineer的博客 4306

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

JDK8的 ConcurrentHashMap 源码分析

本文深入解读了ConcurrentHashMap的源码实现,重点分析了其线程安全机制和核心操作方法。文章首先介绍了关键成员变量如MAXIMUM_CAPACITY、DEFAULT_CAPACITY等,并详细解释了sizeCtl变量的四种状态含义。在初始化部分,说明了无参构造不做实际数组创建,而有参构造会根据输入值计算2的整数次幂容量。对于put操作,文章阐述了其通过CAS自旋、锁链表头节点等方式保证线程安全,并分析了元素添加、链表树化条件(数组长度≥64且链表长度≥8)等过程。

m0_70325779的博客 358

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

来看看对《ConcurrentHashMap》总结

ConcurrentHashMap 是 Java 并发编程中线程安全且高性能的哈希集合,核心解决了 HashMap 线程不安全、Hashtable 锁粒度太粗的痛点。本文基于 JDK1.8 版本,从数据结构、putVal 核心插入流程、get 核心查询流程三个维度,拆解其底层实现与并发安全机制。

weixin_48269137的博客 386

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

ConcurrentHashMap一些问题总结

本文介绍了ConcurrentHashMap的put操作为什么可以保证并发操作安全。方法中在判断桶位是空的时候执行CAS操作为什么能保证并发安全,不会出现类似单例模式的时候,但判断后执行的那种问题。以及他们的get方法和keySet方法有什么不同。在并发读的时候有什么问题。

onesingledog的博客 244

Java 8 ConcurrentHashMap的使用原理

ConcurrnetHashMap是J.U.C包里面提供的一个线程安全并且高效的HashMap,所以ConcurrentHashMap在并发编程的场景中使用的频率比较高。ConcurrentHashMap是Map的派生类,API基本和HashMap类似,主要就是get、put这些方法。接下来基于ConcurrentHashMap的put操作来分析ConcurrentHashMap的源码实现。 JD...

yang的博客 1482

HashMap、HashTable 与 ConcurrentHashMap 的区别

【代码】HashMap、HashTable 与 ConcurrentHashMap 的区别。

qq_73360961的博客 1158

万字总结—ConcurrentHashMap源码剖析—put方法

本文分析了ConcurrentHashMap的线程安全实现机制。首先介绍了构造方法的独特之处,它根据并发线程数反向计算初始容量,确保每个线程能操作独立桶位。重点剖析了putVal方法的实现细节:通过CAS操作保证空桶插入的原子性;遇到ForwardingNode节点时会协助扩容;使用synchronized锁处理哈希冲突情况;支持链表和红黑树两种结构处理碰撞。相比HashMap,ConcurrentHashMap通过分段锁、CAS等机制实现了高效的线程安全,避免了全局锁的性能瓶颈。

mengzhongjie66的博客 380

JUC篇·Java 中的 ConcurrentHashMap 与红黑树:深入解析与应用

ConcurrentHashMap 属于 Java 的 java.util.concurrent(JUC)并发包。JUC(java.util.concurrent)包是 Java 中用于处理并发编程的核心工具包。它提供了一系列高效、灵活且线程安全的类和接口,帮助开发者解决多线程环境下数据共享和同步的问题。在现代多核处理器的背景下,有效地利用并发编程可以显著提高程序的性能,而 JUC 包就是实现这一目标的关键所在。在Java的并发编程世界里,ConcurrentHashMap和红黑树都是极为重要的元素。

无所不能的开花组❀ 974

ConcurrentHashMap源码深度解析

ConcurrentHashMap是Java中的线程安全的哈希表实现,它在JDK 1.7和1.8中有着完全不同的实现方式。本文将深入分析JDK 1.8中ConcurrentHashMap的实现原理。使用CAS + synchronized实现同步使用volatile保证可见性使用红黑树优化性能使用多线程协助扩容这些优化使得ConcurrentHashMap成为了一个高性能的线程安全集合类。

lzz的博客 646

HashMap 与 ConcurrentHashMap 源码分析

HashMap 的本质是通过哈希定位桶,并用链表或红黑树处理冲突;它追求单线程下的访问效率,不负责并发协调。线程不安全的根源是复合操作、扩容和内存可见性都没有同步保障。ConcurrentHashMap 则把并发控制下沉到桶级别:空桶使用 CAS,非空桶使用桶首节点锁,读取依赖 volatile 可见性,扩容支持多线程协作。理解这些源码路径后,可以清楚地看到:它并不是“给 HashMap 外面加一把大锁”,而是通过更细粒度的并发算法,在安全性和吞吐量之间取得平衡。

weixin_61898502的博客 465
上一篇: 记一次Java参数传递时值发生变化问题
下一篇: 细说ConcurrentHashMap扩容规则
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值