5分钟 入门AQS

比特寻幽人
• 阅读 1264

AQS 全称:AbstractQueuedSynchronizer,它是JUC并发工具包中 ReentrantLock 、CountDownLatch、CyclicBarrier等这些类的底层实现。此篇我们主要通过ReentrantLock的使用来大体了解AQS底层代码设计原理,不对源码详细赘述。只要对整体的设计方向有清晰了解,再去追踪源码便不是什么难事。阅读本篇之前,需要大家对ReentrantLock 的API有一定了解。

ReentrantLock的lock、await方法底层逻辑

在使用ReentrantLock进行代码块同步,一般都会有如下写法:


ReentrantLock lock = new ReentrantLock(true);
Condition condition = lock.newCondition();

try{
    lock.lock();
    //.....
    condition.await();
    
 }finally{
    lock.unlock();
 }

假设 T1 时刻有10个线程调用同一个ReentrantLock实例的lock()方法, 线程1 先获取锁成功,紧接着线程2 调用lock()方法,发现获取锁失败(通过CAS操作对状态位进行标记),则线程2被封装成Node节点放入AQS双向队列中,并调用LockSupport.park()阻塞挂起。同样的线程3,线程4,...线程10 也阻塞挂起加入队列中。至此在t1时刻 AQS的队列如图1-1

5分钟 入门AQS

T4 时刻线程1执行完毕,调用unlock()方法释放锁并从AQS队列中取出哨兵节点的下一节点,也就是此刻的线程2,并唤醒该线程。线程2再次尝试获取锁,如果锁获取成功将继续执行线程2代码。如果失败会被再次封装成Node节点放入AQS队列中去。看到这里大家可能会有疑问:为什么线程1的锁释放完后唤醒的是线程2,而不是线程3 或者线程 4 呢?这里是因为公平锁与非公平锁的原因,如果采用了公平锁那么将按照先进先出的原则让线程去抢占锁,而非公平锁没有先后顺序的限制。对于ReentrantLock可以通过构造函数的参数进行指定,默认它采用的是非公平锁。

Lock 与 Condition结合使用又是什么样的原理呢?

我们紧接着上面的分析,线程T1时刻获取锁成功后,在T2时刻调用了condition.await()方法时会发生以下4件事情:

  1. 释放锁(通过CAS操作对状态为进行标记)
  2. 阻塞挂起线程1
  3. 线程1封装成Node节点放入条件队列中(注意:此处条件队列和AQS队列不是一回事)
  4. 唤醒AQS队列中阻塞挂起的线程

当其他线程调用condition.signal() 或者 condition.sigalAll() 方法时,会将条件队列的一个或者全部Node节点移到AQS队列中。
一个锁对应一个AQS队列、多个condition、多个条件队列,条件队列的个数是跟随Condition走的。我们通过1-2图来更直观认识 Lock、Condition、AQS队列、条件队列之间的关系。

5分钟 入门AQS

至此ReentrantLock底层使用AQS来实现线程同步的设计已讲解完毕,赶紧撸源码去吧!!!


清山绿水始于尘,博学多识贵于勤。
我有酒,你有故事吗?
公众号:「Java锦囊」。
欢迎一起谈天说地,聊Java。
书写技术文章是一个循序渐进的过程,所以我不能保证每句话、每行代码都是对的,但至少能保证不复制、不粘贴,每篇文章都是自己对技术的认识、细心斟酌总结出来的。乔布斯说:我们在这个星球上的时间都很短,很少有机会去做几件真正伟大的事情,同时要做得好,我必须要趁我还年轻的时候完成这些事。
其实我想说的是,我是一枚程序员,我只想在有限的时间内尽可能去沉淀我这一生中所能沉淀下来的东西。
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java 面试知识点笔记(十二)多线程与并发
问:synchronized和ReentrantLock的区别?ReentrantLock(可重入锁)位于java.util.concurrent.locks包(著名的juc包是由Douglea大神写的AQS抽象类框架衍生出来的应用)和CountDownLatch、FutureTask、Semaphore一样基于AQS实现
Stella981 Stella981
3年前
AQS实现原理分析——ReentrantLock
在Java并发包java.util.concurrent中可以看到,不少源码是基于AbstractQueuedSynchronizer(以下简写AQS)这个抽象类,因为它是Java并发包的基础工具类,是实现ReentrantLock、CountDownLatch、Semaphore、FutureTask等类的基础。 AQS的主要使用方式是继承,子类通
九路 九路
3年前
一行一行源码分析清楚AbstractQueuedSynchronizer
在分析Java并发包java.util.concurrent源码的时候,少不了需要了解AbstractQueuedSynchronizer(以下简写AQS)这个抽象类,因为它是Java并发包的基础工具类,是实现ReentrantLock、CountDownLatch、Semaphore、FutureTask等类的基础。Google一下A
Wesley13 Wesley13
3年前
Java并发之AQS详解
一、概述  谈到并发,不得不谈ReentrantLock;而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)!  类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountD
Wesley13 Wesley13
3年前
Java高级面试必问:AQS 到底是什么?
前言JDK1.5以前只有synchronized同步锁,并且效率非常低,因此大神DougLea自己写了一套并发框架,这套框架的核心就在于AbstractQueuedSynchronizer类(即AQS),性能非常高,所以被引入JDK包中,即JUC。那么AQS是怎么实现的呢?本篇就是对AQS及其相关组件进行分析,了解其原理,并领略大神的优美而又精简
Wesley13 Wesley13
3年前
Java并发(八):AbstractQueuedSynchronizer
先做总结:1、AbstractQueuedSynchronizer是什么?AbstractQueuedSynchronizer(AQS)这个抽象类,是Java并发包 java.util.concurrent 的基础工具类,是实现ReentrantLock、CountDownLatch、Semaphore、FutureTask等类的
Stella981 Stella981
3年前
AQS (AbstractQueuedSynchronizer)源码导读:锁的获得与释放
AQS是什么?AbstractQueuedSynchronizer简称AQS是一个抽象同步框架,可以用来实现一个依赖状态的同步器。Providesaframeworkforimplementingblockinglocksandrelatedsynchronizers(semaphores,events,etc)th
Wesley13 Wesley13
3年前
Java 多线程与并发(七):ReentrantLock 与 ReentrantReadWriteLock
ReentrantLock我们已经通过前几章学会了synchronized和AQS等相关只是。下面我们继续来学习ReentrantLock这个并发工具类,如果你已经了解了AQS的机制,那么你学习ReentrantLock将会非常轻松。背景Synchronized关键字虽然在JDK1.6
Stella981 Stella981
3年前
ReetrantLock源码分析
ReentrantLock类的大部分逻辑,都是其均继承自AQS的内部类Sync实现的啥是AQS:Java并发编程核心在于java.concurrent.util包而juc当中的大多数同步器实现都是围绕着共同的基础行为,比如「等待队列、条件队列、独占获取、共享获取」等,而这个行为的抽象就是基于AbstractQueuedSynchron
Wesley13 Wesley13
3年前
Java中的AQS到底是什么?高级面试必问!
前言JDK1.5以前只有synchronized同步锁,并且效率非常低,因此大神DougLea自己写了一套并发框架,这套框架的核心就在于AbstractQueuedSynchronizer类(即AQS),性能非常高,所以被引入JDK包中,即JUC。那么AQS是怎么实现的呢?本篇就是对AQS及其相关组件进行分析,了解其原理,并
Wesley13 Wesley13
3年前
AQS源码详细解读
AQS源码详细解读\TOC\基础在讲解AQS之前,有几个额外的知识需要了解。知道了这些,才能明白AQS框架中很多代码的道理。CAS相关知识通过标识位进行线程挂起的并发编程范式MPSC队列的实现技巧欢迎加入技术交流群186233599讨论交流,也欢迎关注笔者公众号:风火说。<!