AQS-abs学习笔记

在这里插入图片描述

1.AQS类定义

1.AQS 是个抽象类,就是给各种锁子类继承用的,AQS 定义了很多如何获得锁,如何释放锁的抽象方法,目的就是为了让子类去实现;
2.继承了 AbstractOwnableSynchronizer,AbstractOwnableSynchronizer 的作用就是为了知道当前是那个线程获得了锁,方便监控用的
获得锁的线程set进来就好了:setWxclusiveOwnerThread(thread)
3.同步队列:主要作用阻塞获取不到锁的线程,并在适当时机释放这些线程。。当多个线程都来请求锁时,某一时刻有且只有一个线程能够获得锁(排它锁),那么剩余获取不到锁的线程,都会到同步队列中去排队并阻塞自己,当有线程主动释放锁时,就会从同步队列头开始释放一个排队的线程,让线程重新去竞争锁
条件队列:ConditionObject,条件队列和同步队列的功能一样,管理获取不到锁的线程,底层数据结构也是链表队列,但条件队列不直接和锁打交道,但常常和锁配合使用,是一定的场景下,对锁功能的一种补充

2.AQS基本属性

1.同步器简单属性:
state:int型,所有继承 AQS 的锁都是通过这个字段来判断能不能获得锁,能不能释放锁
2.同步队列属性:
head
tai
nextWaiter:只是一个标识符,表示当前节点是共享还是排它模式
3.条件队列属性:
firstWaiter
lastWaiter
nextWaiter:下一节点的指向
4.公用node:即是同步队列的节点,又是条件队列的节点,在入队的时候,我们用 Node 把线程包装一下,然后把 Node 放入两个队列中
waitStatus:当前节点的状态
nextWaiter:在同步队列中只是一个标识符,表示当前节点是共享还是排它模式;在条件队列中表示下一节点的指向

3.Condition条件队列

1.假设我们有一个有界边界的队列,支持 put 和 take 方法,需要满足:
a:如果试图往空队列上执行 take,线程将会阻塞,直到队列中有可用的元素为止;
b:如果试图往满的队列上执行 put,线程将会阻塞,直到队列中有空闲的位置为止。
注:a、b中线程阻塞都会到条件队列中去阻塞

2.await():使当前线程一直等待,直到被 signalled 或被打断
3.带等待超时时间的:awaitNanos(long nanosTimeout) --返回的 long 值表示剩余的给定等待时间,如果返回的时间小于等于 0 ,说明等待时间过了
4.唤醒方法:signal()、signalAll()

5.当以下四种情况发生时,条件队列中的线程将被唤醒:
a.有线程使用了 signal 方法,正好唤醒了条件队列中的当前线程;
b.有线程使用了 signalAll 方法;
c.其它线程打断了当前线程,并且当前线程支持被打断;
d.被虚假唤醒 (即使没有满足以上 3 个条件,wait 也是可能被偶尔唤醒)。
注:被唤醒时,有一点需要注意的是:线程从条件队列中苏醒时,必须重新获得锁,才能真正被唤醒

4.AQS同步器的状态

1.state 是锁的状态,是 int 类型,子类继承 AQS 时,都是要根据 state 字段来判断有无得到锁,比如当前同步器状态是 0,表示可以获得锁,当前同步器状态是 1,表示锁已经被其他线程持有,当前线程无法获得锁;
2.waitStatus 是节点(Node)的状态,种类很多,一共有初始化 (0)、CANCELLED (1)、SIGNAL (-1)、CONDITION (-2)、PROPAGATE (-3)
CANCELLED (1):被取消
SIGNAL (-1):同步队列中的节点在自旋获取锁的时候,如果前一个节点的状态是 SIGNAL,那么自己就可以阻塞休息了,否则自己一直自旋尝试获得锁
CONDITION (-2):表示当前 node 正在条件队列中,当有节点从同步队列转移到条件队列时,状态就会被更改成 CONDITION
PROPAGATE (-3):无条件传播,共享模式下,该状态的进程处于可运行状态

5.获取锁

获取锁最直观的感受就是使用 Lock.lock () 方法来获得锁,最终目的是想让线程获得对资源的访问权
Lock 一般是 AQS 的子类,lock 方法根据情况一般会选择调用 AQS 的 acquire 或 tryAcquire 方法:
acquire 方法 AQS 已经实现了。acquire 方法制定了获取锁的框架,先尝试使用 tryAcquire 方法获取锁,获取不到时,再入同步队列中等待锁
tryAcquire方法 AQS 中直接抛出一个异常,表明需要子类去实现,子类可以根据同步器的 state 状态来决定是否能够获得锁;

5.1 acquire 排它锁

acquire()方法流程见整体架构图中红色场景:
1.尝试执行一次 tryAcquire,如果成功直接返回,失败走 2;
2.线程尝试进入同步队列,首先调用 addWaiter 方法,把当前线程放到同步队列的队尾;
3.接着调用 acquireQueued 方法,两个作用,1:阻塞当前节点,2:节点被唤醒时,使其能够获得锁;
4.如果 2、3 失败了,打断线程
addWaiter:把新的节点追加到同步队列的队尾。在 addWaiter 方法中,并没有进入方法后立马就自旋,而是先尝试一次追加到队尾,如果失败才自旋,因为大部分操作可能一次就会成功

5.2 acquireQueued阻塞当前线程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值