07天:同步器__(01)AbstractQueuedSynchronizer__介绍

在这里插入图片描述

前言

  • 如果你想深入研究Java并发的话,那么AQS一定是绕不开的一块知识点,Java并发包很多的同步工具类底层都是基于AQS来实现的

    • 比如我们工作中经常用的Lock工具ReentrantLock、栅栏CountDownLatch、信号量Semaphore等,而且关于AQS的知识点也是面试中经常考察的内容

      • ReentrantLock

      • ReentrantReadWriteLock

      • CountDownLatch

      • Semaphore

      • SynchronousQueue

      • FutureTask

    • 所以,无论是为了更好的使用还是为了应付面试,深入学习AQS都很有必要。

  • CAS机制:

    • CAS是乐观锁的一种思想,它假设线程对资源的访问是没有冲突的,同时所有的线程执行都不需要等待,可以持续执行。

    • 如果有冲突的话,就用比较+交换的方式来检测冲突,有冲突就不断重试。

  • ++CAS原理++:

    • CAS的全称是Compare-and-Swap,也就是比较并交换

    • 它包含了三个参数:V,A,B,V表示要读写的内存位置,A表示旧的预期值,B表示新值,当执行CAS时,只有当V的值等于预期值A时,才会把V的值改为B,

    • 这样的方式可以让多个线程同时去修改,但也会因为线程操作失败而不断重试,对CPU有一定程序上的开销。

      在这里插入图片描述

AQS简介

  • AQS,全名AbstractQueuedSynchronizer,是一个抽象类的队列式同步器

    • 它的内部通过维护一个状态volatile int state(共享资源)

    • 和一个FIFO线程等待队列来实现同步功能。

  • state用关键字volatile修饰,代表着该共享资源的状态一更改就能被所有线程可见

    • 而AQS的加锁方式本质上就是多个线程在竞争state

    • 当state为0时代表线程可以竞争锁

    • 不为0时代表当前对象锁已经被占有,其他线程来加锁时则会失败,加锁失败的线程会被放入一个FIFO的等待队列中

      • 这些线程会被 UNSAFE.park() 操作挂起,等待其他获取锁的线程释放锁才能够被唤醒。
  • 而这个等待队列其实就相当于一个CLH队列,用一张原理图来表示大致如下:

    在这里插入图片描述

基础定义

  • AQS支持两种资源分享的方式:

    • Exclusive(独占,只有一个线程能执行,如ReentrantLock)

    • Share(共享,多个线程可同时执行,如Semaphore、CountDownLatch)。

  • 自定义的同步器继承AQS后,只需要实现共享资源state的获取和释放方式即可

    • 其他如线程队列的维护(如获取资源失败入队/唤醒出队等)等操作,AQS在顶层已经实现了
方法
  • AQS代码内部提供了一系列操作锁和线程队列的方法,主要操作锁的方法包含以下几个:

    • compareAndSetState():

      • 利用CAS的操作来设置state的值
    • tryAcquire(int):

      • 独占方式获取锁。

      • 成功则返回true;

      • 失败则返回false。

    • tryRelease(int):

      • 独占方式释放锁。

      • 成功则返回true;

      • 失败则返回false。

    • tryAcquireShared(int):

      • 共享方式释放锁。

      • 负数表示失败;0表示成功,但没有剩余可用资源;

      • 正数表示成功,且有剩余资源。

    • tryReleaseShared(int):

      • 共享方式释放锁。

      • 如果释放后允许唤醒后续等待结点返回true,否则返回false。

  • 像ReentrantLock就是实现了自定义的tryAcquire-tryRelease,从而操作state的值来实现同步效果。

内部Node节点
  • 除此之外,AQS内部还定义了一个静态类Node,表示CLH队列的每一个结点,该结点的作用是对每一个等待获取资源做了封装,包含了需要同步的线程本身、线程等待状态…

  • 我们可以看下该类的一些重点变量:

    static final class Node {
        /** 表示共享模式下等待的Node */
        static final Node SHARED = new Node();
        /** 表示独占模式下等待的mode */
        static final Node EXCLUSIVE = null;
    
        /** 下面几个为waitStatus的具体值 */
        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;
    
        volatile int waitStatus;
        
         /** 表示前面的结点 */
        volatile Node prev;
         /** 表示后面的结点 */
        volatile Node next;
         /**当前结点装载的线程,初始化时被创建,使用后会置空*/
        volatile Thread thread;
         /**链接到下一个节点的等待条件,用到Condition的时候会使用到*/
        Node nextWaiter;
    }
    
waitStatus
  • 代码里面定义了一个表示当前Node结点等待状态的字段waitStatus,该字段的取值包含了CANCELLED(1)、SIGNAL(-1)、CONDITION(-2)、PROPAGATE(-3)、0,这五个值代表了不同的特定场景:

    • CANCELLED:表示当前结点已取消调度。当timeout或被中断(响应中断的情况下),会触发变更为此状态,进入该状态后的结点将不会再变化。

    • SIGNAL:表示后继结点在等待当前结点唤醒。后继结点入队时,会将前继结点的状态更新为SIGNAL(记住这个-1的值,因为后面我们讲的时候经常会提到)

    • CONDITION:表示结点等待在Condition上,当其他线程调用了Condition的signal()方法后,CONDITION状态的结点将从等待队列转移到同步队列中,等待获取同步锁。(注:Condition是AQS的一个组件,后面会细说)

    • PROPAGATE:共享模式下,前继结点不仅会唤醒其后继结点,同时也可能会唤醒后继的后继结点。

    • 0:新结点入队时的默认状态。

  • 也就是说,当waitStatus为负值表示结点处于有效等待状态,为正值的时候表示结点已被取消

  • 在AQS内部中还维护了两个Node对象head和tail,一开始默认都为null

    private transient volatile Node head;
    
    private transient volatile Node tail;   
    
总结
  • 讲完了AQS的一些基础定义,我们就可以开始学习同步的具体运行机制了

  • 为了更好的演示,我们用ReentrantLock作为使用入口,一步步跟进源码探究AQS底层是如何运作的

  • 这里说明一下,因为ReentrantLock底层调用的AQS是独占模式,所以下文讲解的AQS源码也是针对独占模式的操作

  • 好了,热身正式结束,来吧。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、 1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READmE.文件(md如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值