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. IE播放音频踩坑之路---待修改

    在其他浏览器都是兼容的!在IE9就是显示一个黑色的框上面有个X 音乐无法播放   要显示播放界面的话,要添加 controls 属性(控件属性)例子:<audio src="xxx.m ...

  2. Ubuntu18.04 内核升级

    查看当前版本  在终端输入以下命令并回车 uname -sr  可以发现当前内核为 Linux 4.15.0-88-generic 查看目前最新的稳定内核  访问 The Linux Kernel A ...

  3. Vulnhub系列:chili

    0x01 靶机信息 靶机:chili难度:简单下载:https://www.vulnhub.com/entry/chili-1,558/ 靶机描述: 0x02 信息收集 nmap扫描存活主机确定靶场i ...

  4. ProE许可、PTC许可、Creo许可、许可分析、分析许可

    Pro/Engineer操作软件(又简称ProE)是美国参数技术公司(PTC)旗下的CAD/CAM/CAE一体化的三维软件,Creo是美国PTC公司于2010年10月推出CAD设计软件包,creo是P ...

  5. 网络支持IPV6地址测试校验与思考

    概述 大背景:随着移动端的快速扩张,互联网的规模越来越广阔,早于2011年耗尽的IPV4地址越来越无法满足互联网的网络地址需求,IPV6地址推广进入快车道.实际情况:近期公司应上级部门邀请对公司的主域 ...

  6. mac下复制文件路径

    快捷键: option+command+C

  7. Mac中显示及隐藏文件和文件夹的方法

    一.方法一 直接在文件或文件夹名前面的加一个'.'点号,然后系统会弹出修改确认对话框,点好就行了. 隐藏文件 解除隐藏可以通过方法三显示所有隐藏文件,找到该文件去掉开头的'.',然后通过方法二来解除隐 ...

  8. Excel与MySQL数据库的导入与导出

    应用场景 在许多时候,我们希望数据能够很好地在各个系统之间转移,同时便于非专业人员阅读,如果程序员一点点打字导出的话,不知道要打到什么时候,于是我们便采用日常工作中常用的Excel表格来作为媒介,将数 ...

  9. linux字符编码防止乱码

    一:linux字符编码 en_US.UTF-8 : 美式英文,utf-8 zh_CN.UTF-8 临时优化 export LANG=zh_CN.UTF-8 : 设置编码 永久优化 vim /etc/l ...

  10. 一起玩转玩转LiteOS组件:TinyFrame

    摘要:TinyFrame是一个简单的用于解析串口(如 UART.telnet.套接字等)通信数据帧的库. 本文分享自华为云社区<LiteOS组件尝鲜-玩转TinyFrame>,作者:Lio ...