AQS(AbstractQueuedSynchronizer)是Java中java.util.concurrent包中提供的一个用于构建锁和其他同步组件的框架。它是很多同步控制类的基础,比如ReentrantLock、Semaphore、CountDownLatch、ReadWriteLock等都是基于AQS来实现其同步功能的。
AQS的原理和组件
AQS使用一个整型的volatile变量(称为state)来表示同步状态,并且提供了一系列用于管理这个状态的方法。它的核心思想是,如果一个线程请求的操作需要等待一段不确定的时间,那么这个线程应该被阻塞,并且放入到AQS内部维护的一个等待队列中。以下是AQS的主要组件和原理:
1、同步状态(State):这个状态是由一个volatile int变量表示的,可以表示资源的数量、锁的持有情况等。同步器基于该状态进行控制。
2、节点和队列:在AQS中,每一个等待的线程都会被包装成一个节点(Node)并添加到队列中。AQS底层维护了一个CLH队列来管理所有等待的线程,一个线程节点的入队和出队是通过一种无锁的方式进行的,即CAS操作。
3、排它锁和共享锁:AQS支持两种同步方式——排它(Exclusive)和共享(Shared)。排它锁模式下,每次只有一个线程能够执行;共享锁模式下,多个线程可同时执行。
4、获取和释放方法:AQS定义了一系列方法来管理同步状态,包括acquire、release、acquireShared、releaseShared等。这些方法会调用同步器实现的tryAcquire、tryRelease、tryAcquireShared、tryReleaseShared方法来了解是否应该授予线程同步状态。
5、阻塞和唤醒:无法获取同步状态的线程将会被阻塞。AQS使用LockSupport提供的park和unpark方法来实现线程的挂起和唤醒。
AQS的工作流程
1、尝试获取资源:当一个线程尝试获取资源时,AQS会尝试使用tryAcquire方法来获取同步状态。这个操作是基于CAS的,从而保证了原子性。
2、队列排队:如果尝试失败,AQS会构建一个节点,并将线程以及状态信息封装在该节点中,然后将它加到节点队列中。
3、自旋和阻塞:被包装到节点中的线程将会在在一定条件下自旋尝试获取资源,如果自旋失败则会被park挂起,等待被唤醒。
4、释放资源:释放资源时,调用的是release或者releaseShared方法,它会再次尝试修改同步状态,并在修改成功后,将队列中等待的线程唤醒。
5、唤醒后继续尝试:被唤醒的线程(节点)将尝试获取资源,如果获取成功则从队列中移除节点并执行线程,如果失败则可能会重新挂起。
本文作者:whitebear
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!