AQS(AbstractQueuedSynchronizer) 框架源码解析

什么是AQS

用来构建锁或其他同步器组件的重量级基础框架及整个 JUC体系的基石,通过内置的 CLH队列的变种来完成资源获取线程的排队工作,将每条要去抢占资源的线程封成一Node节点来实现锁的分配,有一个 int 的 state 变量表示持有锁的状态,通过 CAS 完成对 state 变量的修改 0表示没有,1表示阻塞, 大于1表示可重入锁

AQS

AQS 内部体系架构

AQS

继承结构

AQS 内部 state 变量就是代表是否阻塞 0 表示没有人使用,可以获取锁, 1 表示有人在使用,阻塞中, 大于1 是可重入锁

内部结构

内部类 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;
        /** 等待 condition唤醒 */
        static final int CONDITION = -2;
        /** 共享式同步状态获取将会无条件传播下去 */
        static final int PROPAGATE = -3;
        /** 初始为0, 状态为上面的几种 */
		volatile int waitStatus;
		/** 前置节点 */
		volatile Node prev;
		/** 后置节点 */
		volatile Node next;

属性说明
属性说明

AQS 同步队列基本结构

同步队列基本结构

源码解析

从常用的 ReentrantLock 开始解读,假设有三个线程,分别代表三个人在银行办理业务,但是只有一个业务窗口

源码解析

创建 ReentrantLock , 有公平锁和非公平锁.默认创建非公平锁

源码解析

公平锁与非公平锁的lock()方法唯一的区别就在于公平锁在获取同步状态时多了一个限制条件

公平锁与非公平锁区别
限制条件 hasQueuedPredecessors() 其他方法一致
hasQueuedPredecessors() 是公平锁加锁时判断等待队列中是否存在有效节点的方法

public final boolean hasQueuedPredecessors() {
    // The correctness of this depends on head being initialized
    // before tail and on head.next being accurate if the current
    // thread is first in queue.
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

本次以非公平锁开始分析

解析

抢锁

假设A线程直接抢占成功,BC线程则进行后续抢占,进入 acquire(int arg) 方法

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

进入第一个判断方法后发现父类使用模板模式,要求子类必须重写该方法,不然直接抛异常

源码解析

进入非公平锁重写的方法发现直接调用了 nonfairTryAcquire(int acquires) 方法

final boolean nonfairTryAcquire(int acquires) {
    //获取当前线程
    final Thread current = Thread.currentThread();
    //获取state状态
    int c = getState();
    if (c == 0) {
        //比较并交换,将state改为1
        if (compareAndSetState(0, acquires)) {
            //设置为当前线程占用
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //判断占用的线程是否为当前线程(可重入性)
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

此时线程B执行完后会返回false
在 acquire 方法的判断内, !tryAcquire(arg) = true
所以继续执行后面的 addWaiter(Node.EXCLUSIVE) , 参数 Node.EXCLUSIVE = null

源码解析

private Node addWaiter(Node mode) {
    //创建一个node节点,线程为B, waitState为0
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    //此时 tail 尾结点 为null
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    //直接执行该方法创建队列
    enq(node);
    return node;
}

private Node enq(final Node node) {
    //自旋操作
    for (;;) {
        //第一次 tail 为null
        //第二次 tail = head
        Node t = tail;
        if (t == null) { // Must initialize
            //创建一个空的哨兵结点(占位用), thread = null, 并将 head指向该节点
            if (compareAndSetHead(new Node()))
                //将尾节点指向头结点
                tail = head;
        } else {
            //将B节点的前节点指向 head 节点
            node.prev = t;
            //通过CAS将 tail 指向 B 节点
            if (compareAndSetTail(t, node)) {
                //将哨兵节点的下一节点指向B节点
                t.next = node;
                return t;
            }
        }
    }
}

执行完后队列结构

执行完后队列结构

同理,C线程进入队列,tail尾结点指向C节点,B节点next指向C, C节点 prev指向B,最后队列结构

源码解析

返回 B节点或C节点后继续进行判断
后续判断

final boolean acquireQueued(final Node node, int arg) {
    //取消排队,可能线程不愿意等待了
    boolean failed = true;
    try {
        boolean interrupted = false;
        //自旋操作
        for (;;) {
            // 假设该 Node 为B, 则 p 为head哨兵节点
            final Node p = node.predecessor();
             //由于A线程没有释放锁
            //tryAcquire(arg) 会跟上面一样继续返回 false,没有抢占到锁
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            //第一次shouldParkAfterFailedAcquire方法将哨兵节点waitState=-1
            //第二次shouldParkAfterFailedAcquire方法返回true,继续执行
            //执行parkAndCheckInterrupt()方法时直接阻塞线程,不再执行后续操作
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

private final boolean parkAndCheckInterrupt() {
    //线程阻塞,等待获取通行证
    LockSupport.park(this);
    //在调用unpark方法后再向下执行
    return Thread.interrupted();
}

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    // 第一次为 0
    // 第二次为 -1
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL) //Node.SIGNAL = -1
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
         //第二次直接返回true
        return true;
    if (ws > 0) {
        /*
         * Predecessor was cancelled. Skip over predecessors and
         * indicate retry.
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        /*
         * waitStatus must be 0 or PROPAGATE.  Indicate that we
         * need a signal, but don't park yet.  Caller will need to
         * retry to make sure it cannot acquire before parking.
         */
         // 将哨兵节点的 waitState 赋值为 -1
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

此时 B和 C线程都将阻塞在 parkAndCheckInterrupt() 方法内,等待A线程执行完释放锁唤醒其他线程

解锁

A线程执行完毕,调用unlock()方法

public void unlock() {
    sync.release(1);
}

public final boolean release(int arg) {
    //判断是否完全释放锁,并重置状态
    if (tryRelease(arg)) {
        Node h = head;
        //哨兵节点的 waitState 此时为 -1
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

protected final boolean tryRelease(int releases) {
    //假设只获取了一次锁,则 c = 0
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        //将当前占用线程设为null
        setExclusiveOwnerThread(null);
    }
    //设置锁占用情况
    setState(c);
    return free;
}

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; // -1
    if (ws < 0)
        //将哨兵节点的waitState改为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.
     */
     //B 节点, waitState 为 0
    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)
        //解锁线程 B C, 获取到通行证
        LockSupport.unpark(s.thread);
}

回到前面线程抢锁阻塞处

在 A线程执行完unlock()方法后, 在前面说的 B 和 C 线程阻塞处获取到通行证,继续执行返回 true

源码解析

final boolean acquireQueued(final Node node, int arg) {
    //取消排队,可能线程不愿意等待了
    boolean failed = true;
    try {
        boolean interrupted = false;
        //自旋操作
        for (;;) {
            final Node p = node.predecessor();
            //此时 state 为 0 ,tryAcquire(arg)方法中进行抢占锁
            //成功抢占的将占用线程设为当前线程,并修改 state为 1
            if (p == head && tryAcquire(arg)) {
       //设置哨兵节点为当前节点,当前节点的线程和前节点设为null,变为新的哨兵节点
                setHead(node);
                //并将之前的哨兵节点下一节点设为null帮助GC
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            //没抢占到的线程继续在parkAndCheckInterrupt方法等待通行证
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                //获取通行证后继续执行
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

假设B 线程抢占成功,则判断成立,执行 selfInterrupt() 方法处理线程 B 业务

源码解析

最后队列结构为

源码解析

阅读源码需要一步一步走, 一定要自己画流程图理解,这样才能更加深入的理解整体流程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值