一 AQS同步队列实现分析
AQS是一个
1 同步队列
AQS是通过一个内部的FIFO的同步队列来管理同步状态,当线程获取锁失败的时候,当前想线程以及当前线程的状态等信息,会被构造成一个节点加入到同步队列的尾部,然后阻塞当前线程。那么这个节点保存哪些信息呢?
当前线程的引用、等待状态以及当前节点的前驱节点和后继节点。
同步器中存在两种引用:指向首节点的引用和指向尾节点的引用.
首节点是成功获取同步状态的节点,当首节点释放同步状态的时候,将会唤醒后继节点,当后继节点成功获取同步状态以后会将自己设置为首节点。关于首节点和尾节点的设置有一下两点需要说下:
a.首节点是成功获取同步状态的节点,因为只有一个线程可以成功获取同步状态,因此设置首节点不需要CAS设置。
b.一般情况下,会有多个获取锁失败,而获取锁失败的节点会被设置为尾节点,这里线程是通过CAS设置尾节点的,同一时刻必须保证只能一个线程加入到队列尾部,将尾节点的引用指向当前线程的节点.当成功设置为尾节点以后,只有正式设置成功以后,该节点才能与之前的尾节点建立连接。
2 独占式获取锁和释放锁
关于独占式获取锁,.首先调用acquire(int arg)方法。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
线程调用tryAcquire方法去获取同步状态,tryAcquire方法是需要子类自己实现的,当获取同步状态失败以后,调用addWaiter(Node.EXCLUSIVE)方法将当前线程创建为节点加入到队列尾部
/**
* Creates and enqueues node for current thread and given mode.
*
* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
* @return the new node
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure