AbstractQueuedSynchronizer同步器是实现JUC核心基础组件,因为 定义了一套多线程访问共享资源的同步器框架。前面几篇文章中JUC同步工具中都利用AQS构建自身的阻塞类。AQS解决了子类实现同步器时涉及的大量细节问题,例如获取同步状态、FIFO同步队列等;同时采用模板方法模式,AQS实现大量通用方法,子类通过继承方式实现其抽象方法来管理同步状态。先看看其UML图:

     

  首先从类名看这是一个抽象队列同步器,那么是这样的队列呢?CLH同步队列。

     

  AQS它维护了一个 volatile int state(代表共享资源)和一个 FIFO 线程等待队列(多线程争用资源被阻塞时会进入此队列)。

  通过AQS UML图可知state有三种访问方式:

    

  线程等待队列节点详细结构源码如下:

    

  其中acquire/release、acquireShared/releaseShared 是AQS里面的两对模板方法。以acquire为例跟踪分析具体方法:

    

  获取操作可能是独占的exclusive(ReentrantLock),也可能是非独占的share(Semaphore和CountDownLatch),取决于不同的Synchronizer。

    

  AQS 只是一个框架,具体资源的获取/释放方式交由自定义同步器去实现, AQS 这里只定义了一个接口,具体资源的获取交由自定义同步器去实现了(通过 state 的 get/set/CAS)之所以没有定义成abstract ,是 因 为独 占模 式 下 只 用实现 tryAcquire-tryRelease ,而 共享 模 式 下 只用 实 现tryAcquireShared-tryReleaseShared。如果都定义成abstract,那么每个模式也要去实现另一模式下的接口。不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源 state 的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等), AQS 已经在顶层实现好了。自定义同步器实现时主要实现以下几种方法:        

    1. isHeldExclusively():该线程是否正在独占资源。只有用到 condition 才需要去实现它。

    2. tryAcquire(int):独占方式。尝试获取资源,成功则返回 true,失败则返回 false。

    3. tryRelease(int):独占方式。尝试释放资源,成功则返回 true,失败则返回 false。

    4. tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败; 0 表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。

    5. tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回 false。

  一般来说,自定义同步器要么是独占方法,要么是共享方式,他们也只需实现 tryAcquiretryRelease、 tryAcquireShared-tryReleaseShared 中的一种即可。 但 AQS 也支持自定义同步器同时实现独占和共享两种方式,如 ReentrantReadWriteLock。

  一个获取操作分为两步:

    第一步,Synchronizer判断当期状态是否允许被获得。如果是,就让线程执行;如果不是,获取操作阻塞或者失败。具体判断有Synchronizer的语意决定,可以举例说明:如果想成功获取锁,锁必须是未被占有的;二如果想成功地获取闭锁,闭锁必须未处于终止状态。

    第二步包括了可能需要更新的状态。一个想获取Synchronizer的线程会影响到其他线程是否能够获取它。例如,获取锁的操作将锁的状态从“未被占有”改变为“已被占有”;从Semaphore中获取许可的操作会检索剩余许可的数量。另一方面,一个响应对闭锁的请求操作却不会影响到其他薪酬是否能够获取他,所以获取闭锁的操作不会改变闭锁的状态。

  除以上提到的tryXXX方法需要在子类中重写,其他AQS提供的模板方法可参考显式锁之ReentrantLock实现 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)及相关利用AQS实现的阻塞类的使用。

  

  

    

    

Java并发基础之AbstractQueuedSynchronizer(AQS)的更多相关文章

  1. Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)

    AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...

  2. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  3. Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式

    通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...

  4. 【Java并发编程实战】----- AQS(三):阻塞、唤醒:LockSupport

    在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 ...

  5. Java 并发基础

    Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...

  6. java并发基础(五)--- 线程池的使用

    第8章介绍的是线程池的使用,直接进入正题. 一.线程饥饿死锁和饱和策略 1.线程饥饿死锁 在线程池中,如果任务依赖其他任务,那么可能产生死锁.举个极端的例子,在单线程的Executor中,如果一个任务 ...

  7. java并发基础(二)

    <java并发编程实战>终于读完4-7章了,感触很深,但是有些东西还没有吃透,先把已经理解的整理一下.java并发基础(一)是对前3章的总结.这里总结一下第4.5章的东西. 一.java监 ...

  8. Java并发基础概念

    Java并发基础概念 线程和进程 线程和进程都能实现并发,在java编程领域,线程是实现并发的主要方式 每个进程都有独立的运行环境,内存空间.进程的通信需要通过,pipline或者socket 线程共 ...

  9. java并发基础及原理

    java并发基础知识导图   一 java线程用法 1.1 线程使用方式 1.1.1 继承Thread类 继承Thread类的方式,无返回值,且由于java不支持多继承,继承Thread类后,无法再继 ...

随机推荐

  1. JSP页面实际上就是Servlet

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6513069824690618883/ 前面一直提到了Servlet的内容,也是我们平时理解的后台,这次说一下前台的 ...

  2. 机器学习|线性回归三大评价指标实现『MAE, MSE, MAPE』(Python语言描述)

    原文地址 ?传送门 对于回归预测结果,通常会有平均绝对误差.平均绝对百分比误差.均方误差等多个指标进行评价.这里,我们先介绍最常用的3个: 平均绝对误差(MAE) 就是绝对误差的平均值,它的计算公式如 ...

  3. 设计模式-Java版-全-附代码-超生动实例

    阅读推荐:设计模式-简单篇 项目地址:https://gitee.com/zwtgit/gof23 学习网站推荐: https://refactoringguru.cn/design-patterns ...

  4. Web开发之Servlet

    当一个请求到达服务端,服务器怎么处理? 当一个请求到达服务端时,由服务端的引擎来进行分析.它根据工程名找到工程, 然后拿到URL的资源地址和web.XML文件的所有的进行对比,和哪一个对比上就找到了具 ...

  5. JUC之线程池基础

    线程池 定义和方法 线程池的工作时控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等待其他线程执行完成,再从队列中取出任 ...

  6. [FatFs 学习] SD卡总结-SPI模式

    SD卡为移动设备提供了安全的,大容量存储解决方法.它本身可以通过两种总线模式和MCU进行数据传输,一种是称为SD BUS的4位串行数据模式,另一种就是大家熟知的4线SPI Bus模式.一些廉价,低端的 ...

  7. 【刷题-LeetCode】222. Count Complete Tree Nodes

    Count Complete Tree Nodes Given a complete binary tree, count the number of nodes. Note: Definition ...

  8. JUC之文章整理以及汇总

    JUC文章汇总 JUC部分将学习<JUC并发编程的艺术>和<尚硅谷-大厂必备技术之JUC并发编程>进行博客的整理,各文章中也会不断的完善和丰富. JUC概述 JUC的视频学习和 ...

  9. 数组的sort()排序

    1.sort() 方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串Unicode码点,也就是你不传参进去的话,默认按字符串Unicode码点来排序,而不是按数字大小来排序 2.arr ...

  10. vue项目再HBuilder打包成app后,有ui模块未添加的弹窗

    直接在打包后的mainifst.json的文件夹中加入标注部分,我是这样解决了的