AQS源码剖析

AQS源码剖析

AQS就是AbstractQueuedSynchronizer抽象类,AQS其实就是JUC包下的一个基类,JUC下的很多内容都是基于AQS实现了部分功能,比如ReentrantLock,ThreadPoolExecutor,CountDownLatch,Semaphore,CyclicBarrier等等都是基于AQS实现。

首先AQS中提供了一个由volatile修饰,并且采用CAS方式修改的int类型的state变量。

其次AQS中维护了一个双向链表,有head,有tail,并且每个节点都是Node对象。

static final class Node {
	volatile Node prev;
	volatile Node next;
	volatile Thread thread;

}

内部常用方法:

// 尝试获取独占锁, 需要⼦类实现,获取成功返回true,获取失败返回false
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

//  尝试释放独占锁, 需要⼦类实现,释放成功返回true,释放失败返回false
protected boolean tryRelease(int arg) {
        throw new UnsupportedOperationException();
}

// 尝试获取共享锁, 需要⼦类实现,获取成功返回 1,获取失败返回 -1
protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
}

// 尝试释放共享锁, 需要⼦类实现,释放成功返回 1,释放失败返回 -1
protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
 }

// 添加结点到链表队尾
private Node addWaiter(Node mode) {
        // ......
 }

// 如果addWaiter尝试添加队尾失败,则再次调⽤enq此⽅法⾃旋将结点加⼊队尾
private Node enq(final Node node) {
    // ...
}

// 释放锁时,该⽅法需要负责唤醒后继节点
private void unparkSuccessor(Node node) {
    // ...
}

//检测结点状态,如果可以休眠的话则设置waitStatus=SIGNAL并调⽤LockSupport.park休息;
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    // ......
}

获取锁源码:

public final void acquire(int arg) {
    // 尝试获取锁,比如第一个线程获取到锁了,直接返回,第二个线程没有获取到锁,将自己封装成node节点并添加到队列中
    if (!tryAcquire(arg) &&
    // 注意:节点类型是EXCLUSIVE
	acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
    selfInterrupt();
}
private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            // 通过CAS方式向队列中追加节点
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        // 以上CAS追加如果没有成功,出现并发冲突,也就是说向链表追加节点失败,则进入enq(node)自旋重试。
        enq(node);
        return node;
    }
// 入参:node就是当前线程的node
final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                // 获取前驱节点
                final Node p = node.predecessor();
                // 如果前驱节点是头结点,则再次执行tryAcquire尝试获取锁资源,
                // 说白了紧接着就是当前node节点要执行任务了,尝试获取一下锁,看看能不能获取成功
                if (p == head && tryAcquire(arg)) {
                    // 如果获取成功了,就将当前节点设置为头结点
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                // 如果当前节点不是头结点或者没有获取锁成功,那么就将当前线程挂起
                // 说白了就是你可以先歇歇了,暂时轮不到你的了。
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

释放锁:

释放锁说白了就是当前节点释放锁资源,让后继结点持有锁,执行任务。

public final boolean release(int arg) {
    // 释放锁
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            // 如果释放锁成功,则唤醒后面排队的线程
            unparkSuccessor(h);
        return true;
    }
    return false;
}
// 唤醒后面排队的线程
// 说白了就是改变指针的指向
private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     */
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     */
    // 如果后续节点为null,或者后续节点状态为取消状态,从后往前找到一个有效节点进行唤醒
    // 说白了,就是如果后继结点不是一个有效节点,则会从后往前找
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);// 唤醒和挂起操作底层使用的是UNSAFE类的park()和unpark()方法。
}

posted on 2024-08-31 16:46  ~码铃薯~  阅读(7)  评论(0编辑  收藏  举报

导航