JAVA并发编程与高并发解决方案 - 视频第7章(J.U.C之AQS)~未整理完

java共享锁实现原理及CountDownLatch解析

剖析基于并发AQS的共享锁的实现(基于信号量Semaphore)

深入剖析基于并发AQS的(独占锁)重入锁(ReetrantLock)及其Condition实现原理

AQS共享锁应用之Semaphore原理

深入浅出AQS之共享锁模式

java AQS的实现原理(大部分同步类都依赖AQS实现)


转自 https://www.jianshu.com/p/99f1c01f3226
很详细!

1、J.U.C 之 AQS

1.1 介绍

AbstractQueuedSynchronizer类(抽象队列同步器),简称AQS,一个用来构建同步器的框架 。从JDK1.5开始,引入了并发包,也就是J.U.C,大大提高了JAVA程序的并发性能,而AQS则是J.U.C的核心,是并发类中核心部分,它提供一个基于FIFO队列,这个队列可以构建锁或其他相关的同步装置的基础框架。
  
AQS底层数据结构:
在这里插入图片描述

底层采用双向链表,是队列的一种实现,因此可以当做是一个队列。其中Sync queue同步队列,它是双向链表,包括head结点(主要用作后续的调度)与tail结点。Condition queue不是必须的单向链表只有在需要使用到condition的时候才会存在这个单向链表,并且可能存在多个Condition queue

AQS的模板方法有:

 protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
 }
 protected boolean tryRelease(int arg) {
       throw new UnsupportedOperationException();
 }
 protected int tryAcquireShared(int arg) {
       throw new UnsupportedOperationException();
 }
 protected boolean tryReleaseShared(int arg) {
       throw new UnsupportedOperationException();
 }

1.2 设计思路

  • 使用Node实现FIFO队列,可以用于构建锁或者其他同步装置的基础框架

  • 利用了一个int类型表示state状态。在AQS中,存在一个state成员变量,基于AQS有一个同步组件ReentrantLock,在这个组件中,state 表示获取锁的线程数,假如state = = 0 表示无线程获取锁,state == 1表示已有线程获取锁,state > 1 表示锁的数量

  • 使用方法是继承。AQS的设计是基于模板方法使用需要继承AQS并覆写其中的方法

  • 子类通过继承并通过实现它的方法管理其状态{acquire() 和 release()}的方法操纵状态

  • 可以同时实现排它锁共享锁模式(独占、共享)。它的所有子类中,要么实现并使用它的独占功能API,要么实现共享锁的功能,而不会同时使用两套API。即便是它比较有名的子类ReentrantReadWirteLock也是通过两个内部类 读锁写锁 分别使用两套API实现的。AQS在功能上,有独占控制和共享控制两种功能。

  • 在LOCK包中的相关锁(常用的有ReentrantLockReadWriteLock)都是基于AQS来构建.然而这些锁都没有直接来继承AQS,而是定义了一个Sync类去继承AQS,因为面向的是使用用户,而同步器面向的则是线程控制,那么在锁的实现中聚合同步器而不是直接继承AQS就可以很好的隔离二者所关注的事情.

基于以上设计,AQS具体实现的大致思路:

AQS内部维护了一个CLH队列来管理锁,线程首先会尝试获取锁,如果失败,会将当前线程以及等待状态等信息包装成Node结点加入同步队列(Sync queue)中。接着通过CAS不断循环尝试获取锁条件是当前结点为head直接后继才会尝试,如果失败则会阻塞自己,直到自己被唤醒;而当持有锁的线程,释放锁的时候,会唤醒队列中后继线程。基于这些基础的设计和思路,JDK提供了许多基于AQS的子类。

独占式锁过程总结:

AQS的模板方法acquire通过调用子类自定义实现的tryAcquire获取同步状态失败后 --> 将线程构造成Node节点(创建一个独占式节点 )(addWaiter) --> 将Node节点添加到同步队列对尾(addWaiter) --> 前驱节点 是头节点 的节点才会以自旋的方式尝试获取锁(acquirQueued)。如果该节点的前驱不是头节点 或者 该节点的前驱节点是头节点单获取同步状态失败,则判断当前线程需要阻塞,如果需要阻塞则需要被唤醒过后才返回。在释放同步状态时,同步器调用tryRelease(int arg)方法释放同步状态,然后唤醒 头节点的 后继节点

共享式锁过程总结:

共享式获取与独占式获取的最主要区别在于 同一时刻 能否有多个线程同时获取到同步状态。通过调用acquireShared(int arg)方法可以共享式得获取同步状态。

同步器调用tryAcquireShared(int arg)方法尝试获取同步状态,其返回值为int类型,当返回值大于0时,表示能够获取同步状态。因此,在共享式获取的自旋过程中,成功获取同步状态并且退出自旋的条件就是tryAcquireShared(int arg)方法返回值大于等于0。共享式释放同步状态状态是通过调用releaseShared(int arg)方法

CountDownLatchReentrantReadWriteLockSemaphore等都是共享式获取同步状态的。


之后未整理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值