AQS(抽象队列同步器AbstractQueuedSynchronizer)—非公平锁


非公平锁(实现类:NonfairSync)

// 默认非公平锁
ReentrantLock lock = new ReentrantLock();
try {
    lock.lock();
    // do something
} finally {
    lock.unlock();
}

加锁:lock.lock();

/**
 * 加锁
 */
final void lock() {
    // CAS为原子操作,比较STATE值是否为0,是则设置值为1,返回true,否则返回false
    if (compareAndSetState(0, 1))
        // 设置当前线程为锁的拥有者(仅有一个线程可进入此逻辑)
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // 其他线程,等待,继续获取锁
        acquire(1);
}
等待获取锁:acquire(1)
public final void acquire(int arg) {
    if (!tryAcquire(arg) && // 尝试获取锁,获取成功则返回true,方法结束
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 获取锁失败后,把当前线程封装为节点,添加到同步等待队列中,开始自旋,直到获取到锁
        selfInterrupt(); // 给当前线程添加中断标志,告诉开发者当前线程被中断唤醒,而不是被unpark唤醒
}
尝试获取锁:tryAcquire(arg)
/**
 * 尝试获取锁
 */
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}
// 非公平的方式尝试获取锁(就是会插队,后面来的线程可能先获取锁,此处决定了锁的不公平性)
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 状态=0,说明锁已被释放
    if (c == 0) {
        // 后面进来的线程,可能刚好遇到锁被释放,执行以下CAS,就能获取锁
        if (compareAndSetState(0, acquires)) {
            // 设置当前线程为锁的拥有者(仅有一个线程可进入此逻辑)
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 判断当前线程是否为锁的拥有者(可重入锁,拥有锁的线程可重复多次获取锁)
    else if (current == getExclusiveOwnerThread()) {
        // 累加锁的拥有者获取锁的次数
        int nextc = c + acquires;
        if (nextc < 0) // 溢出
            // 当获取锁的次数达到最大Integer.MAX_VALUE,再增加就会溢出,小于0,此时抛错(一般情况下是忘记释放锁导致的)
            throw new Error("Maximum lock count exceeded");
        // 设置当前锁的获取次数
        setState(nextc);
        // 获取锁成功
        return true;
    }
    // 获取锁失败
    return false;
}
添加线程到队列中:acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
/**
 * 把当前线程封装为节点,添加到同步等待队列中
 */
private Node addWaiter(Node mode) {
    // mode=null,因此node仅封装了当前线程的信息
    Node node = new Node(Thread.currentThread(), mode);
    // 获取尾节点
    Node pred = tail;
    if (pred != null) {
        // 当前节点 的 前置节点 指向 尾节点( tail <- node)
        node.prev = pred;
        // CAS为原子操作,比较尾节点是否为tail,是则设置值为node,返回true,否则返回false
        if (compareAndSetTail(pred, node)) {
            // 尾节点 的 后置节点 指向 当前节点( tail <-> node),双向链表(环状链表)构建完成,当前节点成功变成尾节点
            pred.next = node;
            return node;
        }
    }
    // 同步队列为空,初始化同步队列(链表结构)
    enq(node);
    return node;
}
/**
 * 开始自旋,直到获取到锁。
 * 1、如果直到获取到锁,线程都没有被park,则返回false
 * 2、如果没有获取到锁,且线程
 */
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        // 自旋,乃为高大上的说法;死循环,不雅
        for (;;) {
            // 获取前置节点
            final Node p = node.predecessor();
            // 如果前置节点就是头节点,那么就尝试获取锁
            if (p == head && tryAcquire(arg)) {
                // 获取锁成功,设置当前节点为头节点
                setHead(node);
                p.next = null; // help GC
                failed = false;
                // 线程没有中断
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) && // 获取锁失败后,是否应该被park
                parkAndCheckInterrupt()) // 应该被park,park当前线程
                interrupted = true; // 当前线程被中断唤醒,而不是被unpark唤醒
        }
    } finally {
        // 如果出现异常,且获取锁失败
        if (failed)
            // 将当前节点从同步队列中移除
            cancelAcquire(node);
    }
}
是否阻塞当前线程:shouldParkAfterFailedAcquire(p, node)
/**
 * 获取锁失败后,是否应该被park。
 * 这个方法可绕了
 */
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    // 获取前置节点的等待状态
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        /*
         * 如果前置节点的等待状态为Node.SIGNAL(值为-1),那么说明当前节点可以被park了
         */
        return true;
    if (ws > 0) {
        /*
         * 如果前置节点的等待状态大于0(大于0只有Node.CANCELLED状态,值为1),
         * 那么说明前置节点已经被取消掉,需要跳过该节点
         */
        do {
            // 设置当前节点 的 前置节点 为 前置节点的前置节点(就是把CANCELLED状态的前置节点从队列中扔掉)
            node.prev = pred = pred.prev;
            // 循环,把前置节点的等待状态为CANCELLED的全部节点都扔掉
        } while (pred.waitStatus > 0);
        // 直到找到一个等待状态不为CANCELLED的节点,将此前置节点的后置节点设置为当前节点(重新整理等待队列为双向链表)
        pred.next = node;
    } else {
        /*
         * 前置节点的状态为不为SIGNAL,也不为CANCELLED,则将前置节点的等待状态设置为SIGNAL,
         * 标志当前节点已经准备好被park了,但是不马上进行park,而是让当前节点再一次尝试获取锁,
         * 以证明当前节点确实需要被park
         */
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    // 不需要被park
    return false;
}
阻塞当前线程:parkAndCheckInterrupt()
/**
 * 阻塞当前线程,当前线程被唤醒(可能被unpark唤醒,可能被interrupt唤醒)
 */
private final boolean parkAndCheckInterrupt() {
    // 阻塞当前线程
    LockSupport.park(this);
    // 返回当前线程是否被中断唤醒
    return Thread.interrupted();
}
取消获取锁:cancelAcquire(node)
private void cancelAcquire(Node node) {
    if (node == null)
        return;
    node.thread = null;

    // 跳过等待状态为CANCELLED的前置节点
    Node pred = node.prev;
    while (pred.waitStatus > 0)
        node.prev = pred = pred.prev;

    // predNext is the apparent node to unsplice. CASes below will
    // fail if not, in which case, we lost race vs another cancel
    // or signal, so no further action is necessary.
    Node predNext = pred.next;

    // Can use unconditional write instead of CAS here.
    // After this atomic step, other Nodes can skip past us.
    // Before, we are free of interference from other threads.
    node.waitStatus = Node.CANCELLED;

    // 如果当前节点是尾节点,则直接移除,把前置节点设为尾节点
    if (node == tail && compareAndSetTail(node, pred)) {
        // 将前置节点的尾节点设为null
        compareAndSetNext(pred, predNext, null);
    } else {
        // If successor needs signal, try to set pred's next-link
        // so it will get one. Otherwise wake it up to propagate.
        int ws;
        if (pred != head // 前置节点 不为 头节点
           && (
               // 且(前置节点的等待状态为SIGNAL 或者 等待状态为其他状态,CAS为SIGNAL)
               (ws = pred.waitStatus) == Node.SIGNAL || 
               (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))
           ) &&
            // 且 前置节点不为空节点(初始化同步队列的头节点为空节点)
            pred.thread != null) {
            // 获取当前节点的后置节点
            Node next = node.next;
            if (next != null && next.waitStatus <= 0)
                // 后置节点不为空 且 CAS前置节点 的 后置节点 为 当前节点 的后置节点
                compareAndSetNext(pred, predNext, next);
        } else {
            // 
            unparkSuccessor(node);
        }

        node.next = node; // help GC
    }
}

释放锁:lock.unlock();