AQS 抽象同步队列的简单理解

前置知识:

可重入锁又叫递归锁,同一个线程在外层方法获取锁的时候,在进入该线程内层方法会自动获取锁,不会因为之前已经获取过还没释放就阻塞   同一个线程可以多次获得同一把锁

每个锁对象都有一个锁计数器和一个指向持有该锁的线程的指针

隐式锁:synchronized

显式锁:ReentrantLock  显式锁指的是需要lock与unlock  加几次就必须解锁几次  不然其他的线程没办法获取锁

LockSupport:线程等待唤醒机制(wait/notify)改良加强版

传统:就是before   locksupport出现之前的用法

synchronized与wait  notify

1、wait和notify必须要跟synchronized一起使用  否则不合法

2、一定是先阻塞再有人唤醒

condition与await与signal

他们都有两个约束1、线程都要先持有锁,2必须先等待后唤醒,线程才能被唤醒

after:

LockSupport:通过park   unpark 来阻塞和唤醒线程  不需要显式的加锁解锁了

通过许可证来控制            而且可以先通知再阻塞

为什么可以先唤醒线程后阻塞线程?

因为Unpark获得了一个凭证,之后再调用park方法 ,就可以名正言顺的凭证消费,故不会阻塞

为什么唤醒两次后阻塞两次,但是最终结果还会阻塞线程?

因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark效果一样,只会增加一个凭证,而调用两次park需要消费两个凭证,证不够,不能放行  

两个车  只有一个通行证,证不够,所以不能通行。

正题:AQS抽象同步队列

AbstractQueuedSynchronizer:抽象队列同步器

AQS是什么?  ----->变量+队列  是ReentrantLock  、 CountDwnLatch ReentrantReadWriteLock的、Semaphore的带头大哥 是一种统一的规范

为什么有AQS->有阻塞就需要排队,实现排队就必然需要队列

AQS是个队列控制的同步器  队列里面呢  装的是线程节点  

AQS=state+CLH队列

Node=waitStatus+前后指针

从ReentrantLock入手来分析AQS

ReentrantLock加锁过程:1、尝试加锁  2.加锁失败,线程入队列 3、线程入队列后,进入阻塞状态

lock()   第一个线程占用

tryAcquire(arg)

addWaiter(Node.EXCLUSIVE)

acquireQueued(addWaiter(Node.EXCLUSIVE),arg))

在锁里面有一个state字段跟一个当前线程的字段用来做标志

队列中  有一个头结点一个尾结点   第一个节点是一个没有数据的节点  让他作为头结点  每一次进来一个线程就让第一个节点指向他   然后他成为尾结点

比方线程A此时占用了资源   线程B(此时在同步队列中)多次请求无果后  会被locksport给park(挂起)住  此时才算是真正的在“排队”坐稳了位置了

A办完业务了  此时要unlock    会将 “当前占用线程”改为null   并且设置state为0

此时会唤醒h  也就是抽象同步队列的头结点  头结点去唤醒下一个节点  也就是此时的B   B此时会被唤醒  被唤醒之后B会继续尝试去抢占资源  此时A已经离开   并且State为0  B成功抢占到资源

C继续B的流程

然后会让B节点变成新的哨兵节点占位  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值