AQS简介
- 原名 AbstractQueuedSynchronizer 即队列同步器 是构建锁和其他同步组件的基础框架(如ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch)
- AQS解决了子类实现同步器时涉及当的大量细节问题,例如获取同步状态、FIFO同步队列 自定义同步器在实现时只需要实现共享资源state的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了,所以使用AQS不仅能够极大地减少实现工作,而且也不必处理在多个位置上发生的竞争问题
- 只能在一个时刻发生阻塞,从而降低上下文切换的开销,提高了吞吐量
- AQS通过内置的FIFO同步队列来完成资源获取线程的排队工作,如果当前线程获取同步状态失败(锁)时,AQS则会将当前线程以及等待状态等信息构造成一个节点(Node)并将其加入同步队列,同时会阻塞当前线程,当同步状态释放时,则会把节点中的线程唤醒,使其再次尝试获取同步状态
深入源码 看看有哪些方法
- getState()
返回同步状态的当前值
- setState(int newState)
设置当前同步状态
- compareAndSetState(int expect, int update)
使用CAS设置当前状态,该方法能够保证状态设置的原子性
自定义同步器主要实现以下几个方法
- tryAcquire(int arg)
独占式获取同步状态,获取同步状态成功后,其他线程需要等待该线程释放同步状态才能获取同步状态
- tryRelease(int arg)
独占式释放同步状态
- tryAcquireShared(int arg)
共享式获取同步状态,返回值大于等于0则表示获取成功,否则获取失败
- tryReleaseShared(int arg)
共享式释放同步状态
- tryReleaseShared(int arg)
当前同步器是否在独占式模式下被线程占用,一般该方法表示是否被当前线程所独占
- acquire(int arg)
独占式获取同步状态,如果当前线程获取同步状态成功,则由该方法返回,否则,将会进入同步队列等待,该方法将会调用可重写的tryAcquire(int arg)方法
- acquireInterruptibly(int arg)
与acquire(int arg)相同,但是该方法响应中断,当前线程为获取到同步状态而进入到同步队列中,如果当前线程被中断,则该方法会抛出InterruptedException异常并返回
- tryAcquireNanos(int arg,long nanos)
超时获取同步状态,如果当前线程在nanos时间内没有获取到同步状态,那么将会返回false,已经获取则返回true
- acquireShared(int arg)
共享式获取同步状态,如果当前线程未获取到同步状态,将会进入同步队列等待,与独占式的主要区别是在同一时刻可以有多个线程获取到同步状态
- acquireSharedInterruptibly(int arg)
共享式获取同步状态,响应中断
- tryAcquireSharedNanos(int arg, long nanosTimeout)
共享式获取同步状态,增加超时限制
- release(int arg)
独占式释放同步状态,该方法会在释放同步状态之后,将同步队列中第一个节点包含的线程唤醒
- releaseShared(int arg)
共享式释放同步状态
CLH
CLH同步队列是一个FIFO双向队列,AQS依赖它来完成同步状态的管理, 当前线程如果获取同步状态失败时,AQS则会将当前线程已经等待状态等信息构造成一个节点(Node)并将其加入到CLH同步队列,同时会阻塞当前线程, 当同步状态释放时,会把首节点唤醒(公平锁),使其再次尝试获取同步状态。 在CLH同步队列中,一个节点表示一个线程,它保存着 线程的引用(thread)、状态(waitStatus)、前驱节点(prev)、后继节点(next),其数据结构如下