深入AbstractQueuedSynchronized(AQS)源码

本文深入探讨了AbstractQueuedSynchronized(AQS)的源码,它是多线程同步的基础,用于实现如ReentrantLock、Semaphore、CountDownLatch等并发工具类。AQS维护了一个FIFO等待队列,并提供了独占和共享模式的获取与释放锁的方法。文章还提到了AQS的关键数据结构Node及acquire、release、releaseShared等核心方法。

AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch等等

源码

盗用一张图,来源http://www.cnblogs.com/waterystone/p/4920797.html
image

AQS通过维护一个private volatile int state,并提供getState(),setState(),compareAndSetState()等方法,让子类对共享变量state进行读写,从而实现以下方法:
1. tryAcquire:获取排它锁。
2. tryRelease: 释放排它锁。
3. tryAcquireShared:获取共享锁。
4. tryReleaseShared:释放共享锁。
5. isHeldExclusively:判断是否为排它策略。

以上5个方法在ReenterLock、ReadWriteLock、CountDownLatch等类中都有实现,到时候再具体分析。
首先来看下AQS中的一个重要数据结构,Node

    static final class Node {
        // 共享锁节点
        static final Node SHARED = new Node();

        // 排它锁节点
        static final Node EXCLUSIVE = null;

        //---------------下面很关键-----------

        // CANCELLED表示该线程不参与竞争了,只有CANCELLED>0,也只有这个状态是表示没用的node
        static final int CANCELLED =  1;

        // 表示该节点的下一个节点需要被唤醒
        static final int SIGNAL    = -1;

        // 表示该节点wait condition
        static final int CONDITION = -2;

        // 这个状态只有共享锁有,表示共享锁需要传播
        static final int PROPAGATE = -3;

        // 取值为CANCELLED、SIGNAL、CONDITION、PROPAGATE、0
        // 0表示啥也不是,用于初始化
        volatile int waitStatus;

        /**
        * 前驱指针,很有用,能够将状态为CANCELLED的节点跳过,直接挂到最近的SIGNAL节点后面
        */
        volatile Node prev;

        /**
        * 用于唤醒后继节点
        */
        volatile Node next;

        // 记录该节点对于的线程
        volatile Thread thread;

        /**
         * 下一个等待condition的节点
         */
        Node nextWaiter;

        // 省略一下方法
    }

下来看AQS中的一下几个重要方法:

  1. acquire
    /**
     * 获取排它锁,忽略中断。方法会调用tryAcquire来获取锁,如果没有获取,则会将当前线程
     * 添加到阻塞队列中,期间可能会被不断阻塞,唤醒并调用tryAcquire,直到tryAcquire获取到锁
     */
    public final void acquire(int arg) {
        // 先调用tryAcquire尝试获取一次,如果获取到锁,则返回true
        // 如果tryAcquire返回false,则将当前线程加入阻塞队列,并不断尝试获取锁
        // 如果在排队过程中被中断,那acquireQueued返回true,那么会执行selfInterrupt中断当前线程。
        if (!tryAcquire(arg) && 
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))// 如果
            selfInterrupt();
    }

    /**
    * 这个方法由子类实现,一般实现fair与unfair两种策略
    */
    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

    /**
    * 将当前线程与mode打包成一个Node,并添加到等待队列的队尾。
    */
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);

        // 使用CAS尝试将当前节点添加到队尾
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }

        // 如果队列没有初始化或者添加失败,则调用enq方法
        enq(node);
        return node;
    }

    /**
     * 这里使用经典的轮询CAS方式,将node添加到队尾。如果队列没有初始化,顺便初始化队列。
     * @param node the node to insert
     * @return node's predecessor
     */
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // tail==null表示未初始化
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

    /**
     * 为一个已经在等待队列中的Node获取排它锁
     */
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {

                // 获取该节点的前驱节点
                final Node p = node.predecessor();

                // 如果前驱节点是head,并且获取到了锁,则将前驱节点删除
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }

                // 寻找休息点,即从当前节点往head的方向找,跳过所有waitStatus为CANCELLED的节点,直接link到最近的waitStatus为SIGNAL的节点后面。
                // 找到休息点之后,将当前线程park起来,并返回Thread.interrupted()。
                // 如果parkAndCheckInterrupt返回true,那将interrupted置位true。
                // ********这里会被release唤醒,然后重新竞争
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            // 如果失败了,则将当前node从队列中移除。如果该node的next node挂到最近的有效pre node后面,跳过node到最近有效节点间的无效node(waitStatus>0的node)
            if (failed)
                cancelAcquire(node);
        }
    }
  1. release
    /**
     * 释放一个排它锁。
     */
    public final boolean release(int arg) {
        // 如果成功释放锁
        if (tryRelease(arg)) {
            // 获取head node,waitStatus == 0 表示空队列
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);// 唤醒下一个node
            return true;
        }
        return false;
    }

    /**
     * 由子类实现
     */
    protected boolean tryRelease(int arg) {
        throw new UnsupportedOperationException();
    }


    /**
     * 唤醒node的后继节点
     *
     */
    private void unparkSuccessor(Node node) {
        // 如果waitStatus<0,则先将node的waitStatus置成0,因为node是需要release的node
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);


        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;

            // 从tail往node遍历,找一个waitStatus<0的有效节点
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }

        // 如果找到了需要唤醒的节点,则唤醒。
        // ********这里唤醒了之后,仍然需要争抢锁,如果没抢到,还是会继续等待下一次唤醒。
        if (s != null)
            LockSupport.unpark(s.thread);
    }
  1. 3.
    /**
     * 获取共享锁
     *
     */
    public final void acquireShared(int arg) {
        // 若果没获取到锁,tryAcquireShared返回值<0,则将当前线程加入等待队列
        // 如果当前线程获取到了,但是没有其它线程可以获取了(理解为信号量用完了),tryAcquireShared返回0
        // 如果当前线程获取到了,其它线程也可以获取(理解为信号量没用完),tryAcquireShared返回值>0
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }

    /**
    * 尝试获取共享锁,由子类重写。
    */
    protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }

     /**
     * 在队列中获取共享锁
     */
    private void doAcquireShared(int arg) {
        // 将当前线程创建一个mode为SHARED的node
        final Node node = addWaiter(Node.SHARED);

        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    // 如果获取到了,将p出队,使当前节点成为head,并让后继节点也尝试获取。这是与抢占式的区别。
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    /**
     * 将node设置为head,并且如果propagate>0,则继续唤醒后继节点
     */
    private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // Record old head for check below
        setHead(node);
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
            (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            if (s == null || s.isShared())
                doReleaseShared();// 唤醒后继节点
        }
    }

    /**
     * 唤醒后继节点,并传播下去
     */
    private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                //如果head的状态为SIGNAL,尝试将其状态变成0,并唤醒后继节点
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue; 
                    unparkSuccessor(h);
                }
                //如果head的状态为0,则将其状态变成PROPAGATE
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;           
            }
            if (h == head)//head发送过改变,则循环;如果head不变,则break
                break;
        }
    }
  1. releaseShared
    /**
     * 释放共享锁
     */
    public final boolean releaseShared(int arg) {
        // tryReleaseShared释放成功返回true
        if (tryReleaseShared(arg)) {
            doReleaseShared(); //执行子类重写的doReleaseShared方法
            return true;
        }
        return false;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值