AbstractQueuedSynchronizer源码分析 前提 AQS(java.util.concurrent.locks.AbstractQueuedSynchronizer)是并发编程大师Doug Lea创作的用来构建锁或者其他同步组件(信号量.事件等)的基础框架类.在J2SE 1.5的java.util.concurrent包(下称JUC包)中,大部分的同步器(例如锁,屏障等等)都是基于AbstractQueuedSynchronizer类(下称AQS类)这个简单的框架(说实话,作为…
CountDownLatch是AbstractQueuedSynchronizer中共享锁模式的一个的实现,是一个同步工具类,用来协调多个线程之间的同步.CountDownLatch能够使一个或多个线程在等待另外一些线程完成各自工作之后,再继续执行.CountDownLatch内部使用一个计数器进行实现线程通知条件,计数器初始值为进行通知线程的数量.当每一个通知线程完成自己任务后,计数器的值就会减一.当计数器的值为0时,表示所有的通知线程都已经完成一些任务,然后在CountDownLatch上所…
在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概念,主要讲了AQS的排队区是怎样实现的,什么是独占模式和共享模式以及如何理解结点的等待状态.理解并掌握这些内容是后续阅读AQS源码的关键,所以建议读者先看完我的上一篇文章再回过头来看这篇就比较容易理解.在本篇中会介绍在独占模式下结点是怎样进入同步队列排队的,以及离开同步队列之前会进行哪些操作.AQS为在独占模…
通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快的理解其他的方式.虽然说AbstractQueuedSynchronizer源码有一千多行,但是重复的也比较多,所以读者不要刚开始的时候被吓到,只要耐着性子去看慢慢的自然能够渐渐领悟.就我个人经验来说,阅读AbstractQueuedSynchronizer源码有几个比较关键的地方需要弄明白,分别是…
通过前面三篇的分析,我们深入了解了AbstractQueuedSynchronizer的内部结构和一些设计理念,知道了AbstractQueuedSynchronizer内部维护了一个同步状态和两个排队区,这两个排队区分别是同步队列和条件队列.我们还是拿公共厕所做比喻,同步队列是主要的排队区,如果公共厕所没开放,所有想要进入厕所的人都得在这里排队.而条件队列主要是为条件等待设置的,我们想象一下如果一个人通过排队终于成功获取锁进入了厕所,但在方便之前发现自己没带手纸,碰到这种情况虽然很无奈,但是它…
警告⚠️:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳. Java的内置锁一直都是备受争议的,在JDK1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略,但是与Lock相比synchronized还是存在一些缺陷的:虽然synchronized提供了便捷性的隐式获取锁释放锁机制(基于JVM机制),但是它却缺少了获取锁与释放锁的可操作性,可中断.超时获取锁,且它为独占式在高并发场景下性能大打折扣. 如何自己来实现一个同步 自旋…
经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习之AQS框架(一)概述> <Java并发包源码学习之AQS框架(二)CLH lock queue和自旋锁> <Java并发包源码学习之AQS框架(三)LockSupport> 分析源码是非常枯燥乏味的一件事,其实代码本身其实就是最好的说明了,因此基本都是贴出一些代码加上一些注释,…
本文将主要讲述 AbstractQueuedSynchronizer 的内部结构和实现逻辑,在看本文之前最好先了解一下 CLH 队列锁,AbstractQueuedSynchronizer 就是根据 CLH 队列锁的变种实现的,因为本身 AQS 比较复杂不容易看清楚他本身的实现逻辑,所以查看 CLH 队列锁的实现,可以帮助我们理清楚他内部的关系:关于队列锁的内容可以参考 ,CLH.MCS 队列锁简介 : 一.AQS 结构概述 在 JDK 中除 synchronized 内置锁外,其他的锁和同步组…
AQS的源码分析 目录结构 1.什么是CAS ? 2.同步器类结构 3.CLH同步队列 4.AQS中静态内部类Node 5.方法分析 ​ 5.1.acquire(int arg ) ​ 5.2.release(int arg) 释放锁 6.总结 前言 在多线程环境下,我们一般会对临界区资源(共享资源)进行加锁,释放锁,保证同一时刻最多只有一个线程(独占模式),就如去公共厕所里,在使用一个小房间时会加锁避免自己在使用的时候,别人突然闯进来一样,引起不必要的麻烦,在使用完后,再打开锁,其他人才可使用…
ReentrantLock:实现了Lock接口,是一个可重入锁,并且支持线程公平竞争和非公平竞争两种模式,默认情况下是非公平模式.ReentrantLock算是synchronized的补充和替代方案. 公平竞争:遵从先来后到的规则,先到先得非公平竞争:正常情况下是先到先得,但是允许见缝插针.即持有锁的线程刚释放锁,等待队列中的线程刚准备获取锁时,突然半路杀出个程咬金,抢到了锁,等待队列中等待获取锁的线程只能干瞪眼,接着等抢到锁的线程释放锁 ReentrantLock与synchronized比…
目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表结构不同,条件队列是单向链表,同步队列是双向链表. 2.两个队列中等待条件不同,条件队列中线程是已经获取到锁,主动调用await方法释放锁,挂起当前线程,等待某个条件(如IO,mq消息等),同步队列中的线程是等待获取锁,在获取锁失败后挂起等待锁可用. 两者联系: 当等待的某个条件完成,其他线程调用s…
为什么要说AbstractQueuedSynchronizer呢? 因为AbstractQueuedSynchronizer是JUC并发包中锁的底层支持,AbstractQueuedSynchronizer是抽象同步队列,简称AQS,是实现同步器的基础组件,并发包中锁的实现底层就是使用AQS实现,另外大多数人可能不会直接用到AQS, 但是知道其原理对于架构设计还是很有帮助的. 首先我们看一下AQS的类图结构,如下图: 从类图的关系可以看到AQS是一个FIFO的双向队列,内部通过节点head 和…
为什么要说AbstractQueuedSynchronizer呢? 因为AbstractQueuedSynchronizer是JUC并发包中锁的底层支持,AbstractQueuedSynchronizer是抽象同步队列,简称AQS,是实现同步器的基础组件,并发包中锁的实现底层就是使用AQS实现,另外大多数人可能不会直接用到AQS, 但是知道其原理对于架构设计还是很有帮助的. 首先我们看一下AQS的类图结构,如下图: 从类图的关系可以看到AQS是一个FIFO的双向队列,内部通过节点head 和…
AbstactQueuedSynchronizer的基本数据结构 AbstractQueuedSynchronizer的基本数据结构为Node,关于Node,JDK作者写了详细的注释,这里我大致总结几点: AbstractQueuedSynchronizer的等待队列是CLH队列的变种,CLH队列通常用于自旋锁,AbstractQueuedSynchronizer的等待队列用于阻塞同步器 每个节点中持有一个名为"status"的字段用于是否一条线程应当阻塞的追踪,但是status字段并…
一.AbstractQueuedSynchronizer类介绍. 该抽象类有两个内部类,分别是静态不可继承的Node类和公有的ConditionObject类.AbstractQueuedSynchronizer的核心实现是一个双向队列,队列中的每一个元素是一个Node.Node是AbstractQueuedSynchronizer定义的一个内部类.每个Node有一个前向指针prev和一个后向指针.和这个Node关联的thread以及一个状态位.而AbstractQueuedSynchroniz…
学习Java并发编程不得不去了解一下java.util.concurrent这个包,这个包下面有许多我们经常用到的并发工具类,例如:ReentrantLock, CountDownLatch, CyclicBarrier, Semaphore等.而这些类的底层实现都依赖于AbstractQueuedSynchronizer这个类,由此可见这个类的重要性.所以在Java并发系列文章中我首先对AbstractQueuedSynchronizer这个类进行分析,由于这个类比较重要,而且代码比较长,为了…
1.  前言 Java中好多地方用到AbstractQueuedSynchronizer(PS:简称AQS),比如ReentrantLock.线程池,这部分在面试的时候也经常被问到,今天以ReentrantLock为例,通过源码来加深对AQS的理解 2.  lock 通常,我们的用法是这样的: 那么lock(),unlock()到底做了什么,我们并不知晓,接下来一步一步揭开她的神秘面纱 2.1.  lock 可以看到,ReentrantLock默认是NonfairSync(非公平锁) 2.2. …
简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态.然而多线程环境中对状态的操纵必须确保原子性,因此子类对于状态的把握,需要使用这个同步器提供的以下三个方法对状态进行操作: java.util.concurrent.locks.Abstra…
一,Lock 二,关于锁的几个概念 三,ReentrantLock类图 四,几个重要的类 五,公平锁获取 5.1 lock 5.2 acquire 5.3 tryAcquire 5.3.1 hasQueuedPredecessors 5.3.2 compareAndSetState 5.3.3 setExclusiveOwnerThread 5.3.4 getExclusiveOwnerThread 5.4 addWaiter 5.5 acquireQueued 5.5.1 shouldPark…
一.成员变量. 1.目录. 2.state.该变量标记为volatile,说明该变量是对所有线程可见的.作用在于每个线程改变该值,都会马上让其他线程可见,在CAS(可见锁概念与锁优化)的时候是必不可少的.在AQS类中,不会直接操作这个值,而是交由它的子类去操作和定义他的作用. ############################################################################## 3.head与tail.则是这个链表的头尾指针.作用是存储获取锁…
一.前言 在锁框架中,AbstractQueuedSynchronizer抽象类可以毫不夸张的说,占据着核心地位,它提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.所以很有必要好好分析. 二.AbstractQueuedSynchronizer数据结构 分析类,首先就要分析底层采用了何种数据结构,抓住核心点进行分析,经过分析可知,AbstractQueuedSynchronizer类的数据结构如下 说明:AbstractQueuedSynchronizer类底层的数据结…
一.前言 在锁框架中,AbstractQueuedSynchronizer抽象类可以毫不夸张的说,占据着核心地位,它提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.所以很有必要好好分析. 二.AbstractQueuedSynchronizer数据结构 分析类,首先就要分析底层采用了何种数据结构,抓住核心点进行分析,经过分析可知,AbstractQueuedSynchronizer类的数据结构如下 说明:AbstractQueuedSynchronizer类底层的数据结…
在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可见性.在大多数情况下,这些机制都能很好地完成工作,但却无法实现一些更高级的功能,例如,无法中断一个正在等待获取锁的线程,无法实现限定时间的获取锁机制,无法实现非阻塞结构的加锁规则等.而这些更灵活的加锁机制通常都能够提供更好的活跃性或性能.因此,在Java5.0中增加了一种新的机制:Reentrant…
JUC同步器框架AbstractQueuedSynchronizer源码图文分析 前提 Doug Lea大神在编写JUC(java.util.concurrent)包的时候引入了java.util.concurrent.locks.AbstractQueuedSynchronizer,Abstract Queued Synchronizer,也就是"基于队列实现的抽象同步器",一般我们称之为AQS.其实Doug Lea大神编写AQS是有严谨的理论基础的,他的个人博客上有一篇论文<…
一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法.下面开始分析. 二.ThreadPoolExecutor数据结构 在ThreadPoolExecutor的内部,主要由BlockingQueue和AbstractQu…
我们接着上一篇文章继续,本文讲讲解ReentrantLock 公平锁和非公平锁的区别,深入分析 AbstractQueuedSynchronizer 中的 ConditionObject 公平锁和非公平锁 ReentrantLock 默认采用非公平锁,除非你在构造方法中传入参数 true . public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ?…
概要: ReentrantLock类内部总共存在Sync.NonfairSync.FairSync三个类,NonfairSync与FairSync类继承自Sync类,Sync类继承自AbstractQueuedSynchronizer抽象类 对ReentrantLock类的操作大部分都直接转化为对Sync和AbstractQueuedSynchronizer类的操作. 公平锁资源被其他线程占用且不是重入情况,该线程就会添加到同步队列的尾部,而不会先尝试获取资源. 非公平锁会尝试去获取资源,如果此…
JUC源码分析-线程池篇(一):ThreadPoolExecutor Java 中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池.在开发过程中,合理地使用线程池能够带来 3 个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 第三:提高线程的可管理性.线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一…
一.前言 在分析了AbstractQueuedSynchronier源码后,接着分析ReentrantLock源码,其实在AbstractQueuedSynchronizer的分析中,已经提到过ReentrantLock,ReentrantLock表示下面具体分析ReentrantLock源码. 二.ReentrantLock数据结构 ReentrantLock的底层是借助AbstractQueuedSynchronizer实现,所以其数据结构依附于AbstractQueuedSynchroni…
一.前言 有了前面分析的基础,现在,接着分析CyclicBarrier源码,CyclicBarrier类在进行多线程编程时使用很多,比如,你希望创建一组任务,它们并行执行工作,然后在进行下一个步骤之前等待,直至所有的任务都完成,和join很类似,下面,开始分析源码. 二.CyclicBarrier数据结构 分析源码可以知道,CyclicBarrier底层是基于ReentrantLock和AbstractQueuedSynchronizer来实现的,所以,CyclicBarrier的数据结构也依托…