AbstractQueuedSynchronizer源码研读笔记

Spring Wu 843 2021-02-03

AbstractQueuedSynchronizer

AbstractQueuedSynchronizer简称AQS,常见的锁ReetrantLock就是AQS的实现,AQS的本质是一个双向链表。通过headtail都可以操作整个队列。

    +------+  prev +-----+       +-----+
head|      | <---- |     | <---- |     |  tail
    +------+       +-----+       +-----+

在AQS中有主要通过静态内部类Node来实现队列

static final class Node {
        // 节点处于共享模式等待的标记
        static final Node SHARED = new Node();
        
        // 节点处于排他模式等待的标记
        static final Node EXCLUSIVE = null;

        // 线程已经取消等待的标记
        static final int CANCELLED =  1;
        
        // 等待的状态值,标记后续线程需要取消停靠
        static final int SIGNAL    = -1;
        
        // 表示线程处于等待状态
        static final int CONDITION = -2;
        
        // 表示下一个被默认对象的等待状态值应该无条件传播
        static final int PROPAGATE = -3;

        // 线程等待状态
        volatile int waitStatus;

        // 当前节点的上一个节点
        volatile Node prev;

        // 当前节点的下一个节点
        volatile Node next;

        // 当前节点中线程
        volatile Thread thread;

        // 等待节点的后继节点。如果当前节点是共享的,那么这个字段是一个SHARED常量,也就是说节点类型(独占和共享)和等待队列中的后继节点共用一个字段。(注:比如说当前节点A是共享的,那么它的这个字段是shared,也就是说在这个等待队列中,A节点的后继节点也是shared。如果A节点不是共享的,那么它的nextWaiter就不是一个SHARED常量,即是独占的。)
        Node nextWaiter;

        // 是否为共享锁
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        // 返回上一个节点,如果上一个节点为空,则抛出空指针异常
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        // 构造一个节点,添加到等待队列
        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        // 构造一个节点,添加到Condition队列
        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

AbstractQueuedSynchronizer中的属性:

// 当前AQS的头部节点
private transient volatile Node head;

// 当前AQS的尾部节点
private transient volatile Node tail;

// 当前AQS的状态
private volatile int state;

并且分别提供了headtailstatecas方法。标明每次操作替换整个队列的头部和尾部节点的时候,都是原子性操作,而且Node类中的关键属性,也都提供了cas方法。

ReentrantLock与AQS

NonfairSync.lock()

final void lock() {
    // CAS 尝试获取锁
    if (compareAndSetState(0, 1))
        // 当前线程获取锁成功 
        setExclusiveOwnerThread(Thread.currentThread());
    // 获取锁失败
    else
       // 调用AQS的获取锁方法尝试获取锁。如果获取失败,则调用AQS的addWaiter方法,将当前线程添加到等待队列中。
       acquire(1);
}

这里是非公平锁的源码,NonfairSync继承了SyncSync也是ReentrantLock的静态内部类。Sync又继承于AbstractQueuedSynchronizer。所以通过ReentrantLock源码可以看到,利用了AQS将竞争锁失败的线程放入到AQS的等待队列中。其中还有一个公平锁FairSync

FairSync.lock()

 final void lock() {
    acquire(1);
}

与非公平锁的区别就是,没有先去通过CAS获取一遍锁,而是直接走AQS的方法获取锁。这样就保证了同一个线程不会因为每次释放锁而又能立马拿到锁,而是先去队列中排队,等待获取锁。保证了公平性。

AbstractQueuedSynchronizer.acquire(int arg)

public final void acquire(int arg) {
    if (
    // 尝试获取锁,获取成功返回true,凡是false
    !tryAcquire(arg)
    &&
    // 如果获取失败,则将当前线程设置为独占锁添加到等待队列中
    acquireQueued(addWaiter(Node.EXCLUSIVE), arg)){
        // 获取失败,中断当前线程。
        selfInterrupt();
    }
}