学习笔记:AQS

序言

好久没有写文章了,最近太懒了哈哈,今天督促自己写一下AQS的学习笔记吧,因为前段时间刚温习了一遍。

AQS

AQS全称是:AbstractQueuedSynchronizer(抽象的队列同步器),它隶属于我们的JUC包,可以说AQS就是并发类的基类/规范了,很多类都是基于AQS实现的:lock锁,CountDownLatch,CyclicBarrier,Semaphore。

AQS的工作原理:当有线程来获取共享资源时,如果共享资源处于空闲状态,那么该线程就设置为工作线程,共享资源设为锁定状态,如果线程来获取锁,共享资源处于锁定状态,则将当前线程放入队列中并将其阻塞,直到共享资源变成空闲状态,则将其唤醒抢占资源。

AQS中的核心组件:

  • state:一个被volatile修饰的int变量,0表示当前资源处于空闲状态,1表示当前资源处于锁定状态
  • Node:它是用来封装线程的,还包括了指向前一个结点和指向后一个结点的指针,还有一个waitStatus字段用于保存当前Node结点等待的状态,Node还包括两个模式,Shared模式表以共享状态等待锁,EXCLUSIVE模式表以独占状态等待锁。
  • FIFO队列:FIFO基于CLH虚拟的双端队列实现的,FIFO队列其实就是用Node结点以及头尾指针来具体实现。

AQS的具体实现:Lock

lock锁时基于AQS实现的,lock中有一个内部类Sync它继承了AQS类,Sync还有两个子类,一个FairLock公平锁和NoFairLock非公平锁,根据构造函数来创建公平锁和非公平锁,公平锁在获取资源时需要额外判断一个条件:当前队列为空或队列不为空,队列中头结点为当前线程。

lock的lock()方法:

  • 线程来获取锁,判断state是否为0,如果为0则通过cas的方式获取锁,不为0或者cas获取失败则会调用acpuire()方法。
  • acquire()方法:它会调用tryAcquire()方法和acquireQueued()方法
  • tryAcquire()方法:继续尝试抢占锁,判断两个条件:当前state为0则尝试通过cas抢占锁,如果当前线程为已获取锁的线程,则可重入成功,否则获取锁失败
  • acquireQueued():它会先调用一个addWaiter()方法,将当前线程封装成Node结点放入我们的FIFO队列当中,如果是第一次调用FIFO队列的话会先进行初始化(队列中的头结点是一个哨兵结点,后面的才是我们的Node结点),再在队列中尝试获取锁,如果失败的话就调用LockSupport.park()方法将线程阻塞掉。
  • LockSupport:它也是用于阻塞/唤醒线程的类,但它不同于我们的wait,await/notify,signal方法,使用LockSupport阻塞/唤醒线程时并不需要像其他方法一样必须先获取锁,它可以在任意时刻来阻塞/唤醒线程。

lock的unlock()方法:

  • 底层会调用tryRelease方法,将state设为0且将当前占用锁的线程设为null,然后将队列中处于阻塞状态的线程唤醒。

总结

生命不息,学习不止,与君共勉,希望我们都可以拥有美好的前程!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guojunjiang12345

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值