[JUC系列]AQS

AbstractQueuedSynchronizer

AQS是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Semaphore等都是基于AQS的。

核心思想

AQS的核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果请求的共享资源被占用,那么就需要一套线程阻塞以及被唤醒时锁分配机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
在这里插入图片描述

它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。state的访问方式有三种

  1. getState():获取State的值
  2. setState(): 设置State的值
  3. compareAndSetState():使用CAS方式更新State

AQS定义两种资源共享方式

  1. Exclusive(独占,只有一个线程能执行,如ReentrantLock)
  2. Share(共享,多个线程可以同时执行,例如Semaphore/CountDownLatch)
    在这里插入图片描述

不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现共享资源state的获取和释放方式即可,至于具体线程等待的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。自定义同步器实现时主要实现以下几种方法:

  • isHeldExclusicely(): 该线程是否正在独占资源,只有用到condition才需要去实现它。
  • tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败返回false。
  • tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
  • tryAcquireShared(int):共享方式。尝试获取资源,负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
  • tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待节点返回true,否则返回false。

ReentrantLock的实现

state初始化为0,表示未锁定的一个状态,当一个线程lock()时,会调用tryAcquier()
独占锁并将state+1。之后其他线程再想tryAcquire()的时候就会失败,知道该线程unlock()到state=0为止,其它线程才有机会获取该锁。当此线程释放锁前,自己也是可以充入获取此锁(state累加,这就是一个可重入的概念),但是需要注意获取多少次锁就要释放多少次锁,这个就是可重入的概念。

CountDownLatch的实现

任务分为N个子线程去执行,state就初始化为N,N个线程并行执行,每个线程执行完countDown()一次,state就会CAS减一。当N子线程全部执行完毕,state=0,会unpark()主调用线程,主调用线程就会从await()函数返回,继续之前的动作。

一般来说,自定义同步器要么是独占方法,要么是共享方式。但是AQS也支持自定义同步器实现独占和共享两种方式,例如ReentrantReadWriteLock。

在acquire()和acquireShared()两种方式下,线程在等待队列中都是忽略中断的,acquireInterruptibly() acquireSharedInterruptibly()是支持响应中断的。

CountDownLatch源码

在这里插入图片描述

同步类在实现时一般都将自定义同步器(sync)定义为内部类,供自己使用;而sync只用实现资源state的获取-释放方式tryAcquire-tryRelelase,至于线程的排队、等待、唤醒等,上层的AQS都已经实现好了,我们不用关心。

感谢各位大佬的❤️关注+点赞❤️,原创不易,鼓励笔者创作更好的文章

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值