AQS篇一

很多东西都是时看时新,而且时间长了也会忘,所以再来复习下,也会有一些新的角度看法这次来聊下AQS的内容,主要是这几个点,

第一个线程

第一个线程抢到锁了,此时state跟阻塞队列是怎么样的,其实这里是之前没理解对的地方

/**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            // 这里如果state还是0说明锁还空着
            if (c == 0) {
                // 因为是公平锁版本的,先去看下是否阻塞队列里有排着队的
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    // 没有排队的,并且state使用cas设置成功的就标记当前占有锁的线程是我
                    setExclusiveOwnerThread(current);
                    // 然后其实就返回了,包括阻塞队列的head和tail节点和waitStatus都没有设置
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            // 这里就是第二个线程会返回false
            return false;
        }
    }

第二个线程

当第二个线程进来的时候应该是怎么样,结合代码来看

/**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     */
    public final void acquire(int arg) {
        // 前面第一种情况是tryAcquire直接成功了,这个if判断第一个条件就是false,就不往下执行了
        // 如果是第二个线程,第一个条件获取锁不成功,条件判断!tryAcquire(arg) == true,就会走
        // acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

然后来看下addWaiter的逻辑

/**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {
        // 这里是包装成一个node
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        // 最快的方式就是把当前线程的节点放在阻塞队列的最后
        Node pred = tail;
        // 只有当tail,也就是pred不为空的时候可以直接接上
        if (pred != null) {
            node.prev = pred;
            // 如果这里cas成功了,就直接接上返回了
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        // 不然就会继续走到这里
        enq(node);
        return node;
    }

然后就是enq的逻辑了

/**
     * Inserts node into queue, initializing if necessary. See picture above.
     * @param node the node to insert
     * @return node's predecessor
     */
    private Node enq(final Node node) {
        for (;;) {
            // 如果状态没变化的话,tail这时还是null的
            Node t = tail;
            if (t == null) { // Must initialize
                // 这里就会初始化头结点,就是个空节点
                if (compareAndSetHead(new Node()))
                    // tail也赋值成head
                    tail = head;
            } else {
                // 这里就设置tail了
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

所以从这里可以看出来,其实head头结点不是个真实的带有线程的节点,并且不是在第一个线程进来的时候设置的

解锁

通过代码来看下

/**
     * Attempts to release this lock.
     *
     * <p>If the current thread is the holder of this lock then the hold
     * count is decremented.  If the hold count is now zero then the lock
     * is released.  If the current thread is not the holder of this
     * lock then {@link IllegalMonitorStateException} is thrown.
     *
     * @throws IllegalMonitorStateException if the current thread does not
     *         hold this lock
     */
    public void unlock() {
        // 释放锁
        sync.release(1);
    }
/**
     * Releases in exclusive mode.  Implemented by unblocking one or
     * more threads if {@link #tryRelease} returns true.
     * This method can be used to implement method {@link Lock#unlock}.
     *
     * @param arg the release argument.  This value is conveyed to
     *        {@link #tryRelease} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @return the value returned from {@link #tryRelease}
     */
    public final boolean release(int arg) {
        // 尝试去释放
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
    		// 判断是否完全释放锁,因为可重入
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
// 这段代码和上面的一致,只是为了顺序性,又拷下来看下

public final boolean release(int arg) {
        // 尝试去释放,如果是完全释放,返回的就是true,否则是false
        if (tryRelease(arg)) {
            Node h = head;
            // 这里判断头结点是否为空以及waitStatus的状态,前面说了head节点其实是
            // 在第二个线程进来的时候初始化的,如果是空的话说明没后续节点,并且waitStatus
            // 也表示了后续的等待状态
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

/**
     * Wakes up node's successor, if one exists.
     *
     * @param node the node
     */
// 唤醒后继节点
    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.
         */
        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);
    }