吃透Java并发:AQS结构详解及其CLH变种、CLH、MCS

深入理解AQS的CLH队列 我们知道,AQS定义了两种队列,同步等待队列(CLH队列)和条件等待队列(CONDITION队列),在学习AQS的过程中对这两个队列总是有种雾蒙蒙的感觉,到底是怎么入队、阻塞、唤醒、出队的?到底是怎么保证并发安全的? 阅读详情

1、前言

俗话说得好,学会AQS就学会了JUC。今天我们就来了解一下,这个传说中的AQS的内部结构。
(强烈建议英语好的同学直接看AQS的注释!!)

2、AQS的构成

抽象队列同步器(即AQS),通过一系列模板办法为我们实现JUC下各种各样的工具锁提供了基础,通过继承它,我们可以很轻松的实现一把自己的锁。

假如是让我们来实现锁的逻辑,结合synchronized的实现原理,我们很容易得出,我们需要:

  1. 表示线程是否被上锁的状态信息
  2. 线程竞争失败时需要存放的队列
  3. 能让线程进行阻塞/唤醒

有了这三个东西,我们就可以保证线程通过修改可见变量的状态来标识是否被占用,以及上锁失败时线程应该阻塞的地方。

当然,为了知道当前是哪个线程得到了锁资源,我们还需要一个变量来表明当前持锁线程:exclusiveOwnerThread。

2.1 状态信息state

在AQS中,使用了一个被volatile修饰的int类型变量来标识状态信息。

	/**
     * The synchronization state.
     */
    private volatile int state;

在使用过程中,我们可以通过定义volatile的状态来实现不同的逻辑。比如:

  1. ReentrantLock中将state=0表示无锁状态,state>0表示加锁状态。如state=3就代表,有个线程已经持有锁,并且重入了两次。
  2. CountDownLatch中则是在构造器中定义state的大小来实现计数器的功能
  3. Semaphore中也是通过定义state的大小与修改state来实现限流器的功能

通过CAS来修改state的状态,AQS不用申请monitor就能保证线程安全,同时还能实现各种各样不同的功能。

2.2 节点信息Node

线程竞争失败,自然需要在一个地方阻塞等待条件成立。但是直接把Thread放进去队列似乎有点不太合适,既然是队列,就得有节点。于是AQS需要把线程封装成节点信息之后再放进去,这里贴一下Node的成员变量:

		/**
         * 标记节点未共享模式
         * */
        static final Node SHARED = new Node();
        /**
         *  标记节点为独占模式
         */
        static final Node EXCLUSIVE = null;

        /**
         * 在同步队列中等待的线程等待超时或者被中断,需要从同步队列中取消等待
         * */
        static final int CANCELLED =  1;
        /**
         *  后继节点的线程处于等待状态,而当前的节点如果释放了同步状态或者被取消,
         *  将会通知后继节点,使后继节点的线程得以运行。
         */
        static final int SIGNAL    = -1;
        /**
         *  节点在等待队列中,节点的线程等待在Condition上,当其他线程对Condition调用了signal()方法后,
         *  该节点会从等待队列中转移到同步队列中,加入到同步状态的获取中
         */
        static final int CONDITION = -2;
        /**
         * 表示下一次共享式同步状态获取将会被无条件地传播下去
         */
        static final int PROPAGATE = -3;

        /**
         * 标记当前节点的信号量状态 (1,0,-1,-2,-3)5种状态
         * 使用CAS更改状态,volatile保证线程可见性,高并发场景下,
         * 即被一个线程修改后,状态会立马让其他线程可见。
         */
        volatile int waitStatus;

        /**
         * 前驱节点,当前节点加入到同步队列中被设置
         */
        volatile Node prev;

        /**
         * 后继节点
         */
        volatile Node next;

        /**
         * 节点同步状态的线程
         */
        volatile Thread thread;

        /**
         * 等待队列中的后继节点,如果当前节点是共享的,那么这个字段是一个SHARED常量,
         * 也就是说节点类型(独占和共享)和等待队列中的后继节点共用同一个字段。
         */
        Node nextWaiter;

这里我们关注三个点:

  1. 前驱节点: volatile Node prev;
  2. 后继节点:volatile Node next;
  3. 节点同步状态的线程:volatile Thread thread;

在关于AQS竞争与释放流程剖析的时候,这几个东西可是十分重要的。

2.3 阻塞/唤醒

其实这里没有什么好说的,这里AQS使用了LockSupport工具类中的方法,而再进一步就是使用了unsafe中的park和unpark方法。

如果还要进一步就是涉及到由C语言实现的_count(是否阻塞)、_cond(条件变量)、_mutex(互斥锁)。

2.4 当前持有锁线程

在AQS中并没有直接使用一个变量来标识当前持有锁的线程,而是选择继承了另一个抽象类:AbstractOwnableSynchronizer。

在这个类中,主要就是围绕当前持有锁线程变量提供了get/set操作。

public abstract class AbstractOwnableSynchronizer implements java.io.Serializable {
    private static final long serialVersionUID = 3737899427754241961L;

    protected AbstractOwnableSynchronizer() { }

    /**
     * 独占模式同步器的当前持有线程.
     * transient关键字表示属性不参与序列化
     */
    private transient Thread exclusiveOwnerThread;

    protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }

    protected final Thread getExclusiveOwnerThread() {
        return exclusiveOwnerThread;
    }
}


2.5 头结点与尾节点

关于这个,会在AQS多线程下获取与释放流程剖析时进行讲解。

	/**
     * 指向同步等待队列的头节点
     */
    private transient volatile Node head;

    /**
     * 指向同步等待队列的尾节点
     */
    private transient volatile Node tail;


3、CLH队列

CLH队列也是AQS的组成部分。之所以把它单独拎出来讲,是因为CLH是一种算法,而且AQS中是CLH队列的变种。同时CLH队列的优化还有MCS。

在讲CLH队列之前,我们先了解两个前置知识点(我抄来的):

  • SMP(Symmetric Multi-Processor)
    对称多处理器结构,指服务器中多个CPU对称工作,每个CPU访问内存地址所需时间相同。其主要特征是共享,包含对CPU,内存,I/O等进行共享。
    SMP能够保证内存一致性,但这些共享的资源很可能成为性能瓶颈,随着CPU数量的增加,每个CPU都要访问相同的内存资源,可能导致内存访问冲突,
    可能会导致CPU资源的浪费。常用的PC机就属于这种。

  • NUMA(Non-Uniform Memory Access)
    非一致存储访问,将CPU分为CPU模块,每个CPU模块由多个CPU组成,并且具有独立的本地内存、I/O槽口等,模块之间可以通过互联模块相互访问,
    访问本地内存的速度将远远高于访问远地内存(系统内其它节点的内存)的速度,这也是非一致存储访问的由来。NUMA较好地解决SMP的扩展问题,
    当CPU数量增加时,因为访问远地内存的延时远远超过本地内存,系统性能无法线性增加。

3.1 CLH锁

在基础的自旋锁算法下,为了保证公平锁,CLH队列中的申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋。

CLH队列锁是一种基于链表的可扩展、高性能、公平的自旋锁。优点是空间复杂度低,但是在NUMA系统结构下,每个线程有自己的内存,如果前趋结点的内存位置比较远,则性能会大打折扣。

3.2 MCS锁

为了应对这种情况,MCS锁修改了自旋的规则:CLH是在前趋结点的locked域上自旋等待,而MCS是在自己的结点的locked域上自旋等待。正因为如此,它解决了CLH在NUMA系统架构中获取locked域状态内存过远的问题

3.3 AQS中的变种CLH锁

AQS在CLH的基础上进行了变种:CLH是单向队列,其主要特点是自旋检查前驱节点的locked状态。而AQS同步队列是双向队列,每个节点也有状态waitStatus,而其并不是一直对前驱节点的状态自旋,在尝试自旋一次后会将线程阻塞让出CPU时间片,等待前驱节点主动唤醒自己。

4、结尾

事实上这一章都是为了下一章的AQS多线程下获取与释放流程剖析做铺垫,对AQS有了大概的了解,我们在下一章就不至于那么懵逼~

自动驾驶仿真(二)—— 基于PreScan与Simulink的联合仿真 自动驾驶仿真软件介绍二—— PreScan与Simulink联合仿真1. Prescan仿真软件2. Prescan与Simulink联合仿真2. 1 Prescan和matlab软件安装2. 2 联合仿真配置3. 联合仿真实例3.1 一辆不按法规行驶的小车3.2 另一辆的正常行驶的小车3.3 视觉辅助摄像机3.4 传感器检测4. 系列学习视频教程5. 参考学习的书目教材 上一篇博文简单介绍了Carsim与Simulink联合仿真,接着这篇就再继续简单介绍另一款自动驾驶仿真软件Prescan,并且简单做个P 阅读详情

相关推荐

基于Python的网络拓扑图绘制

最近写论文画了许多图,在这里记录一些。当然,如果仅仅是展示性图片的话也可以使用visio,但是这里我仍然想探究一下如何使用pyhon画出美观的网络拓扑图。(1)根据邻接矩阵画出网络拓扑图(2)画出网络拓扑图,并对节点和链路进行表示,包括对节点和链路的标号,颜色区分,以及尺寸区分。

m0_53961910的博客 7095

字节面试官:你知道 CAS,那你有了解过 CLH 和 MCS?和 AQS 又是什么关系呢?

普通自旋锁可能存在的一些问题:饥饿、如何实现公平、CPU 高速缓存频繁同步 CLH 锁 和 MCS 锁是什么?如何解决这些问题以及使用场景

Lorin 洛林的后端技术小站 454

BERTopic模型入门教程(附代码+参数调节)

BERTopic 是一种用于从文本数据中提取主题模型的新型方法。通过结合 BERT嵌入和传统的主题模型来生成语义丰富的主题。传统的主题模型(如LDA)主要依赖于词频矩阵,而 BERTopic 通过预训练语言模型生成高维语义嵌入来捕捉词语间的复杂关系,因此可以更好地处理上下文信息。BERTopic模型可以看作是创建其主题表示的一系列步骤。核心原理如下:就本质而言,BERTopic就是一个拼装框架,可以把每部分都替换成其他模型,只要完成任务即可。

m0_52069102的博客 1万+

【转】自旋锁、排队自旋锁、MCS锁、CLH锁

原文: http://coderbee.net/index.php/java/20131115/577 好文,万一哪天原文的博客关闭链接失效了,转来留底。 自旋锁(Spin lock) 自旋锁是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。 自旋锁适用于锁保护的临界区很小的情况,临界区很小的话,锁占用的时间就很短。 简...

三思而后行 825

MySQL 优化 - index_merge 导致查询偶发变慢

今天遇到了一个有意思的问题,线上数据库 CPU 出现了偶发的抖动。定位到原因是一条查询语句偶发变慢造成的,随后通过调整表中的索引解决。优化器通过某种机制检测到 index_merge 能带来性能提升,某些情况下不会带来提升,反而会耗费更长的时间,属于优化器的缺陷,可以通过调整表中的索引来解决。

分享既学习 1255

欧姆龙 CJ1W-SCU模块使用通配符+结束码实现非固定长度数据的接收

实验设备:CJ2M-CPU33、CJ1W-SCU21、XW2Z-200T 实验目的:了解 CJ1W-SCU 通配符使用 1.硬件接线: CJ1W-SCU21单元号拨码置于8,使用串口1(232口)。 2.软件设置: ① 新建工程,选择PLC型号CJ2M-CPU33,切换到编程模式,如下图: 、 ② 创建I/O并进行相关配置,如下图: ③ 设置为用户设置,协议宏模式,8位数据位,2位停止位,偶校验9600波特率,如下图: 、 ④ 打开CX-Protocal软件,新建工程: .

weixin_42118352的博客 1984

【锁】自旋锁-MCS/CLH队列

1.自旋锁-MCS/CLH队列 之前有写过一篇关于锁的笔记:【锁】公平锁/非公平锁/可重入锁/递归锁/自旋锁/独占锁/共享锁/读写锁 里面关于自旋锁,特别CLH队列并没有提到,故此有了这篇笔记。 2.自旋锁 指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上线文切换的消耗,缺点是循环会消耗CPU 2.1 CAS JUC包里的AtomicInteger类底层用...

aaa_bbb_ccc_123_456的博客 2648

详解大模型微调数据集构建方法(持续更新)

本文详细介绍了大模型微调数据集构建方法,希望能对学习大模型的同学们有所帮助。 文章目录 1. 前言 2. 微调数据集构建方法 2.1 方法一 2.2 方法二 2.3 方法三 2.4 方法四 2.5 方法五

herosunly的博客 28万+

CLH锁与MCS锁

Ticket锁(传送门)的缺点在于扩展性,cpu不断增加扩展时,对于共享变量(当前叫号叫到了几号)的访问会成为系统的瓶颈,共享变量递增导致大量的线程本地缓存被置为无效,需要通过内存总线访问主存刷新本地缓存,会造成拥塞。而CLH锁与MCS锁正式为了解决此瓶颈而衍生的算法。下面我来看一下他们的实现以及对比。 CLH锁 定义 CLH锁是一个可扩展,高性能,公平的基于链表的自旋锁,应用线程仅自旋在本地变量...

阿呆的专栏 684

lammps教程:FeNiCr合金多晶结构建模方法

大家好,我是小马老师。 本文介绍合金多晶模型的建模过程,使用的软件为Atomsk。 Atomsk是一个开源软件,可运行在windows、linux等多种操作系统上,本文使用windows版的Atomsk实现建模,其他操作系统的建模命令基本相同。 建模过程如下: 1. 生成单晶Fe晶胞 atomsk --create fcc 3.65 Fe Fe.xsf 2. 建立多晶节点文件polycrystal.txt 新建一个文本文件polycrystal.txt,文件内容为: box 200 100 200 ran

lammps_jiayou的博客 6658

英飞凌Tricore问题排查01_Det/Reset/Trap排查宝典

软件跑飞进Det或发生Reset或进Trap了,怎么查?有固定套路可以follow吗?英飞凌Tricore又有哪些专门的定位办法?本篇为您娓娓道来。

initiallizer的博客 4416

【算法数据结构专题】「线程锁算法专项」初探CLH队列锁机制原理分析

自旋锁说白了也是一种互斥锁,只不过没有抢到锁的线程会一直自旋等待锁的释放,处于busy-waiting的状态,此时等待锁的线程不会进入休眠状态,而是一直忙等待浪费CPU周期。因此自旋锁适用于锁占用时间短的场合。互斥锁说的是传统意义的互斥锁,就是多个线程并发竞争锁的时候,没有抢到锁的线程会进入休眠状态即【sleep-waiting】,当锁被释放时候,处于休眠状态的一个线程会再次获取到锁。缺点:就是这一些列过程需要线程切换,需要执行很多CPU指令,同样需要时间。如果CPU执行线程切换的时间比锁占用的时间还长,那

世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程。 1005

基于fme和python-docx第三方库批量更新不动产调查表

最近应朋友需要批量更新在不动产成果中提交的各种word报表中的指定数据,根据初步的了解,我做了一个基于fme软件和python-docx第三方库进行一个批量的更新方案。

weixin_43229258的博客 1240

reentrantlock原理_Java并发-锁的应用与原理,看这一篇就够了

推荐阅读:秋招面试总结:Java+并发+Spring+MySQL+分布式+Redis+算法+JVM等手撕并发编程:Synchronized+锁+线程池+内存模型等通过对锁原理的分析,重点分析ReentrantLock和ReentrantReadWriteLock的源码,通过锁的实现更深入的理解AQS。 本文很长,不要指望读10分钟以内看懂锁的原理。需要结合源码反复体会,才会把这块知识吃透。01 提...

weixin_39824020的博客 199

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

CLH锁 、MCS锁

一。引文 1.1 SMP(Symmetric Multi-Processor) 对称多处理器结构,指服务器中多个CPU对称工作,每个CPU访问内存地址所需时间相同。其主要特征是共享,包含对CPU,内存,I/O等进行共享。 SMP能够保证内存一致性,但这些共享的资源很可能成为性能瓶颈,随着CPU数量的增加,每个CPU都要访问相同的内存资源,可能导致内存访问冲突, 可能会导致CPU资源的浪费。常用的PC机就属于这种。 1.2 NUMA(Non-Uniform Memory Access) 非一致存储访问,将CP

huapro.vip的程序人生 606

深度学习工具包 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")

AQS

AQS 前言 在Java中,主要有两种类型的锁,一种是Synchronized,它是基于JVM实现的,还有一种就是基于AQS框架实现的锁,借助于CAS操作。今天主要想讲一下基于AQS实现的锁 在使用锁时,一般会考虑以下几点: 希望这个锁是同一时间只能被一个线程获取的,还是能够多个线程获取。 当几个线程在同时争抢锁的占有权时,怎么处理没有获取到锁的线程 某个线程一直获取不到锁,怎么处理中断 上面的三个问题AQS已经帮我们解决了,锁需要做的只是实现获取和释放锁的方法 在AQS中有一个volatile的变量s

qq_40058686的博客 516

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

AQS: CLH 介绍

AQS内部维护着一个FIFO队列,该队列就是CLH同步队列。 CLH同步队列是一个FIFO双向队列,AQS依赖它来完成同步状态的管理,当前线程如果获取同步状态失败时,AQS则会将当前线程已经等待状态等信息构造成一个节点(Node)并将其加入到CLH同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点唤醒(公平锁),使其再次尝试获取同步状态。 在CLH同步队列中,一个节点表示一个线程,它保存...

csdn1981的专栏 1342

AQS的前菜—详解CLH队列锁

https://blog.youkuaiyun.com/weixin_47184173/article/details/115340014 什么是CLH队列锁 CLH锁其实就是一种基于逻辑队列非线程饥饿的一种自旋公平锁。当多线程竞争一把锁时,获取不到锁的线程,会排队进入CLH队列的队尾,然后自旋等待,直到其前驱线程释放锁。由于是 Craig、Landin 和 Hagersten三位大佬的发明,因此命名为CLH锁。 自旋锁与互斥锁的区别 由于CLH锁是一种自旋锁,那么我们先来看看自旋锁是什么? 自旋锁说白了

yygr的博客 5711

AQS基础——多图详解CLH锁的原理与实现

由于CLH锁是一种自旋锁,那么我们先来看看自旋锁是什么?自旋锁说白了也是一种互斥锁,只不过没有抢到锁的线程会一直自旋等待锁的释放,处于的状态,此时等待锁的线程不会进入休眠状态,而是一直忙等待浪费CPU周期。因此自旋锁适用于锁占用时间短的场合。这里谈到了自旋锁,那么我们也顺便说下互斥锁。这里的互斥锁说的是传统意义的互斥锁,就是多个线程并发竞争锁的时候,没有抢到锁的线程会进入休眠状态即,当锁被释放的时候,处于休眠状态的一个线程会再次获取到锁。

程序员高级码农的博客 1635

并发编程——详解 AQS CLH 锁

AQS 是 JUC 中的核心,其中封装了资源的获取和释放,在我们之前的并发编程之 AQS 源码剖析文章中,我们已经从 ReentranLock 那里分析了锁的获取和释放。但我有必要再次解释 AQS 的核心 CLH 锁。CLH CLH(Craig, Landin, and Hagersten locks): 是一个自旋锁,能确保无饥饿性,提供先来先服务的公平性。CLH锁也是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋。

程序员阿飘 的博客 214

并发编程之AQS中的CLH队列

CLH队列 在AQS类文件的开头,作者添加了很长一段注释,向开发者解释CLH队列,以及AQS对CLH队列的使用。AQS里面的CLH队列是CLH同步锁的一种变形。其主要从两方面进行了改造:节点的结构与节点等待机制。在结构上,AQS类引入了头结点和尾节点,他们分别指向队列的头和尾,尝试获取锁、入队列、释放锁等实现都与头尾节点相关: To enqueue into a CLH lock, you atomically splice it in as new tail. To dequeue, you jus

及时雨的csdn 1487

AQS---抽象队列同步器、CLH锁队列

自旋锁、CLH锁队列、AQS的锁队列,以ReentrantLock为例讲解AQS获取锁原理

qq_73181349的博客 1451

Java 线程知识笔记 (九) 并发框架AQS详解

之前说锁的升级的时候,说到了自旋锁会空转几次尝试等待获取资源,其实这一系列的动作是有一个规范的这个规范叫做同步发生器AbstractQueuedSynchronizer ,简称AQS。同步发生器是用来构建锁用的,可以说是Java中同步组件的基础,在Java JDK的JUC包中:java.util.concurrent。我们常用的ReentrantLock,Semaphore等等用的都是这样一个架构,可以说是这些Lock工具的一个基础。

Smallc0de的博客 360

Java AQS核心数据结构CLH锁以及AQS中对其的改进

CLH锁是对自旋锁的一种改进。// 如果锁未被占用,则设置当前线程为锁的拥有者 while(!// 只有锁的拥有者才能释放锁 owner . compareAndSet(currentThread , null);} }自旋锁在获取锁时,线程会对一个原子变量循环执行方法,直到该方法返回成功即成功获取锁。操作是通过CAS实现的,因此该操作是原子操作。原子性保证了根据最新消息计算出新值,如果与此同时值已由另一个线程更新,则写入失败。因此,这段代码可以实现互斥锁的功能。

tcn760的博客 849

深入剖析Java AQS:CLH锁的原理、实现与优化

自旋锁是互斥锁的一种实现,Java 实现如下方所示。如代码所示,获取锁时,线程会对一个原子变量循环执行 compareAndSet 方法,直到该方法返回成功时即为成功获取锁。compareAndSet 方法底层是通用 compare-and-swap (下称 CAS)实现的。该操作通过将内存中的值与指定数据进行比较,当数值一样时将内存中的数据替换为新的值。该操作是原子操作。原子性保证了根据最新信息计算出新值,如果与此同时值已由另一个线程更新,则写入将失败。因此,这段代码可以实现互斥锁的功能。

资料免费分享,点击名片 383

JAVA多线程之——自旋锁、CLH、MCS

自旋锁学习了解自旋锁之前先回顾一下互斥锁 互斥锁 线程在获取互斥锁的时候,如果发现锁已经被其它线程占有,那么线程就会惊醒休眠,然后在适当的时机(比如唤醒)在获取锁。 自旋锁 那么自旋锁顾名思义就是“自旋”。就是当一个线程在尝试获取锁失败之后,线程不会休眠或者挂起,而是一直在循环检测锁是否被其它线程释放。 区别 互斥锁就是开始开销要大于自旋锁。临界区持锁时间的大小并不会对互斥锁的开销造成影

永不止步 2714
上一篇: 吃透Java并发:一文看懂锁升级流程
下一篇: nginx反向代理导致后端session失效解决方案
我没有在划水
博客等级 码龄7年 81粉丝 42原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值