• AQS-AbstractQueuedSynchronizer


    目录

    AQS简介

    AQS具备的特性

    AQS内部维护属性

    AQS资源共享方式

    AQS队列

    AQS队列中节点状态

     AQS实现的线程等待队列的维护方法

    同步等待队列

     条件等待队列

    Condition


    AQS简介

    上一篇整理,知道了synchronized的使用,以及synchronized的原理,还有管程

    管程就是通过加锁来保证并发安全,用的比较多的,就是MESA

    MESA内部存在同步等待队列和许多的条件等待队列,获取锁失败的线程会进入同步等待队列

    而synchronized是JVM层面对管程的实现,是基于对象的,通过ObjectMonitor来实现,获取锁失败的线程,会进入到cxq队列,这就是同步等待队列,而wait,notify,notifyAll,就是条件等待队列 

    但是synchronized也有缺点:自动加锁解锁,不支持手动解锁;实现比较重

    这是synchronized的缺点,并且没办法改变

    那,在保证性能的前提下,Java层面该怎么实现管程,于是开发大佬就搞出来了接下来的东西

    并发这块,用的很多的锁,除了synchronized,很多人都会想到ReentrantLock,而ReentrantLock也是有基础的,那就是基于AQS

    AQS是什么,就是AbstractQueuedSynchronizer的简写

    java.util.concurrent包中大多数的同步器实现,如Lock、Latch、Barrier,都是围绕着一个共同的基本行为,比如等待队列、条件队列、独占获取、共享资源等等,这些行为的抽象就是基于AQS实现的,AQS是一个抽象同步框架,可以用来实现一个依赖状态的同步器

    AQS具备的特性

    AQS具备如下特性:

    • 阻塞等待队列
    • 共享/独占
    • 公平/非公平
    • 可重入
    • 允许中断

    AQS内部维护属性

    volatile int state

    state表示资源的可用状态,访问state,有三种方式

    getState(), setState(), compareAndSetState()

    AQS资源共享方式

    AQS定义了两种资源共享方式

    • Exclusive-独占,只有一个线程能执行,比如,ReentrantLock
    • Share-共享,多个线程可以同时执行,比如,Semaphore、CountDownLatch

    AQS队列

    AQS有两种队列,分别是同步等待队列和条件等待队列

    同步等待队列主要用于维护获取互斥锁失败时入对的线程

    条件等待队列主要用于,线程调用await()方法时释放锁,进入条件队列,等调用了signal()方法唤醒的时候,会把条件队列中的线程节点移动到同步队列,等待重新获取锁

    AQS队列中节点状态

    AQS定义了五种线程在队列中的节点状态

    • 值为0,初始化状态,表示当前节点在sync队列中,等待获取锁
    • CANCELLED,值为1,表示当前线程被取消
    • SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark
    • CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中
    • PROPAGATE,值为-3,表示当前场场景下后续的acquireshared能够得以执行

     AQS实现的线程等待队列的维护方法

    不同的自定义同步器竞争共享资源的方式不同,自定义同步器在实现时只需要实现共享资源state的获取与释放就可以,至于具体的线程等待队列的维护,比如资源获取失败入队,唤醒出队等等,AQS已经在最顶层实现好了,自定义同步器实现时主要实现以下几种方法

    • isHeldExclusively():该线程是否正在独占资源,只有用到了condition才需要去实现它
    • tryAcquire(int):独占方式,尝试获取资源,成功就返回true,失败就返回false
    • tryRelease(int):独占方式,尝试释放资源,成功就返回true,失败就返回false
    • tryAcquireShared(int):共享方式,尝试获取资源,负数表示失败;0表示成功,但是i没有剩余资源可用;正书表示成功,并且有剩余资源
    • tryReleaseShared(int):共享方式,尝试释放资源,如果释放后允许唤醒后续等待节点返回true,否则返回false

    同步等待队列

    AQS中的同步等待队列,也称为CLH队列,是一种基于双向链表结构的队列,是一种先入先出的等待队列,AQS依赖于CLH队列来完成对同步状态的管理,至于为什么叫CLH队列,那是因为,CLH队列是Craig、Landin、Hagersten三人发明的

    如果当前线程获取同步状态失败,AQS会把当前线程已经等待状态等信息构造成一个节点,并将其加入到CLH队列,同时会阻塞当前线程

    当同步状态被释放时,会唤醒首节点(公平锁),使其在此尝试获取同步状态

    通过signal或者signalAll可以将条件队列中的节点转移到同步队列

     条件等待队列

    AQS中条件等待队列是用单向列表保存的,用nextWaiter来拼接

    调用await()方法阻塞线程

    当前线程存在于同步队列的头节点,调用await()方法进行阻塞,从而就由同步队列转换为了条件队列

    Condition

    可以将Condition通俗的理解为条件队列

    调用Condition#await方法会释放当前持有的锁,然后阻塞当前线程,同时向Condition队列尾部添加一个节点,所以调用Condition#await方法的时候必须持有锁

    调用Condition#signal方法会将Condition队列的首节点移动到阻塞队列尾部,然后唤醒因调用Condition#await方法而阻塞的线程(唤醒之后这个线程就可以去竞争锁了),所以调用Condition#signal方法的时候必须持有锁,持有锁的线程唤醒被因调用Condition#await方法而阻塞的线程

  • 相关阅读:
    R语言使用plot函数可视化数据、使用type参数自定义设置可视化的类型(数据点和线关系的类型)、设置type参数为b则线条将数据点连接起来
    初始化antdv项目,按需引入
    SpringBoot笔记:SpringBoot集成MyBatis实战
    AIOT在数字化转型中的机遇和挑战
    springboot vue3 elementui plus点餐外卖系统源码
    《开源软件的影响力》
    Golang 并发&同步的详细原理和使用技巧
    锐捷Ruijie路由器版本升级
    Python教程:PyQt5需要学习,哪些知识点??
    要做CMMI认证?什么是CMMI资质认证?
  • 原文地址:https://blog.csdn.net/weixin_46097842/article/details/126101291