J.U.C-ReentratLock源码小读(一)

ReentrantLock存在两种实现的方式,公平锁以及非公平锁.默认为非公平锁。
ReentrantLock是依赖于java.util.concurrent.locks.AbstractQueuedSynchronizer实现的

公平锁

获取锁过程

情景一:只有一个线程尝试获取锁(不存在竞争)

java.util.concurrent.locks.ReentrantLock#lock
-> java.util.concurrent.locks.ReentrantLock.FairSync#lock
----> java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire
java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire中就会出现逻辑判断处理了。具体代码如下

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

首先第一个tryAcuire()方法为AQS中的抽象方法,对应公平锁的实现java.util.concurrent.locks.ReentrantLock.FairSync#tryAcquire:

protected final boolean tryAcquire(int acquires) {
    // 获取当前请求所的线程
    final Thread current = Thread.currentThread();
    // 获取锁标识位
    int c = getState();
    if (c == 0) { // 如果为0 -> 表示锁当前为自由状态
        if (!hasQueuedPredecessors() && // 首先判断自己需不需要排队 -> 公平性的体现
                    compareAndSetState(0, acquires)) { // 如果不需要排队 -> 尝试去获取锁(通过CAS)
            setExclusiveOwnerThread(current); // 设置获取锁的线程为当前线程
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) { // 如果锁状态标识位不为0(锁已被持有)
        // 如果持有锁的线程为当前线程
        // 则在锁的标识位上加1
        // 可冲入锁的体现
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#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.
    // AQS中维护了一个双向链表,也就是说队列的结构。
    // 它定义了一个head-头结点,tail-尾结点。在初始化时都为null
    // node(pre, next, thread)
    //
    // head[node(null)] <-> node1(t1) <-> node2(t2)[tail]
    //
    //
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    return h != t && // 判断head 和 tail是否相等。如果在AQS刚被初始化的时候 head == tail,都为null。在此时,AQS刚初始化 所以 t!=h -> false
            ((s = h.next) == null || s.thread != Thread.currentThread());
    // 判断 head.next 即第二个节点是否为 null 或者
    // 第二个节点中的线程是否为当前线程。
    // 首先这里有一个结论 -> 队列中的首节点是不排队的(因为它没有保存任何线程)。
}

hasQueuedPredecessors()获取到结果为false后 即 当前线程不需要排队等待,然后会调用java.util.concurrent.locks.AbstractQueuedSynchronizer#compareAndSetState方法进行CAS操作,如果成功则获取到锁则设置当前锁的持有线程为当前线程,此时我们己经假设当前只有它一个线程,所以至此它获取到了锁并返回true,此时tryAcquire返回true,acquire正常结束。

情景二:锁已经被持有

前几步的执行逻辑相同。需注意的是,此时hasQueuedPredecessors()方法中的h != t依旧为 false及此时Thread2依旧不需要排队(当然,因为除它之外也没有别的线程)。然后Thread2在执行java.util.concurrent.locks.AbstractQueuedSynchronizer#compareAndSetState方式时由于Thread1还未释放锁,所以此时他是失败的,即

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

中的tryAcquire(arg)返回false,此时if语句条件继续判断。
首先java.util.concurrent.locks.AbstractQueuedSynchronizer#addWaiter方法

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
    // 此时由于tail 还处在初始化状态,所以 pred = tail = null
    Node pred = tail;
    if (pred != null) { // false
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#enq方法:

private Node enq(final Node node) {
    for (;;) { // 一个死循环
        Node t = tail;
            if (t == null) { // Must initialize。必须对队列进行初始化
                if (compareAndSetHead(new Node()))
                    // 注意此时将头结点new 了一个Node
                    // 即 头结点中的 线程为null
                    tail = head;
                    // 继续进行下一次循环
            } else {
                node.prev = t;
                // 将新增结点设置在尾部
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    // 此时队列结构为
                    // [head]node0(thread=null) <->node1(thread=thread1)[tail]
                return t;
            }
        }
    }
}

然后执行java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireQueued

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            // for 死循环
            // 取出当前node及node1(thread=thread1)的结点 
            // p = node0(thread=null)
            final Node p = node.predecessor();
            // 此时p == head 为 true 然后尝试进行一个tryAcquire操作及会尝试获取锁
            // 尝试获取锁的原因为:有可能在当前线程入队的时候锁已经被释放了。
            if (p == head && tryAcquire(arg)) {
                // 获取锁成功
                // 将当前节点从队列中移除
                // 但此处有个主意点,主意setHead方法
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
             }
             // 如果当前节点不为队列中的第二个节点 或者 尝试获取锁失败
            if (shouldParkAfterFailedAcquire(p, node) && // 此时返回false -> 即又进行一次循环并尝试获取锁。
                    // park当前线程
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#setHead
setHead方法会将当前node中的thread设置为null
所以至此可得出结论:队列中head节点中的node对象不保存任何Thread

private void setHead(Node node) {
    head = node;
    node.thread = null;
    node.prev = null;
}

java.util.concurrent.locks.AbstractQueuedSynchronizer#shouldParkAfterFailedAcquire

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    // ws 为Node节点中保存的数据,注意此时的pred节点为刚才初始化队列是new出来的,
    // 所以 waitStatus字段为初始默认值0
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL) // static final int SIGNAL    = -1;
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            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.
             */
            // 设置ws为-1
            // 注意:此时设置的为当前节点的pred节点的ws为-1,然后返回false
            // 当第二次进入此方法时,ws为-1,表示此时当前node可以park了。
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

释放锁

java.util.concurrent.locks.ReentrantLock#unlock

--> java.util.concurrent.locks.AbstractQueuedSynchronizer#release

    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            // 释放成功
            Node h = head;
            // 如果头结点不为null 并且 头结点的waitStatus不为0 -> unpark下一个排队的线程
            // 思考:之前thread1将head中的ws设置为-1的时机
            //          此时如果还未被设置为-1表示 thrad还未park。
            //          应为thread1在设置它的pred结点的ws为-1之后还进行了一次自旋操作。如果获取到了锁,那么相应的队列结构也需要调整。也就不会进入park状态。如果thread1进入了park状态那么表示thread1的pred node中的ws必定为-1。依次类推 [head](node1(thread=null, ws=-1)) <-> node2(thread=thread2, ws=-1) <-> node3(thread=thread3, ws=-1)[tail]
            //          
            if (h != null && h.waitStatus != 0)
                // 如果head中的ws不为0时则表示队列中存在排队的线程 -> unpark
             
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

java.util.concurrent.locks.ReentrantLock.Sync#tryRelease

        protected final boolean tryRelease(int releases) {
            // 锁标识 - 1
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            // 为0 则锁没有没当前线程冲入,可以free
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

java.util.concurrent.locks.AbstractQueuedSynchronizer#unparkSuccessor

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)
        // -1 则设置为 0
        // 所以aqs中是以前一个节点的ws是否为-1表示当前节点中的线程是否需要park的
        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;
    }
    // unpark当前节点的下一个节点中的线程
    if (s != null)
        LockSupport.unpark(s.thread);
}

你可能感兴趣的:(J.U.C-ReentratLock源码小读(一))