ReentrantLock 的 lock 办法源码

ReentrantLock 中的 lock 办法,首要调用内部类 Sync 中的笼统 lock 办法。该办法首要有两套完成,一套是公正锁,一套对错公正锁。

公正锁

final void lock() {
    acquire(1);
}

公正锁中,直接调用 acquire 办法。

非公正锁

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

非公正锁中,首要测验将 AQS 中的 state 属性从 0 变成 1,假如成功,则代表获取锁资源成功;否则调用 acquire 办法。

ReentrantLock 的 acquire 办法源码

acquire 办法中没有实践的事务处理,都是在调用其他办法。

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
  1. 首要调用 tryAcquire 办法,测验获取锁资源,假如获取成功,则回来 true,办法结束。假如获取失利,则调用 && 后面的办法。
  2. 调用 addWaiter() 办法,将线程封装到 Node 节点并添加到行列尾部。
  3. 之后再调用 acquireQueued() 办法检查当时排队的 Node 是否在行列的前面,假如在前面,测验获取锁资源。假如没在前面,线程进入到阻塞状况。

ReentrantLock 的 tryAcquire 办法源码

tryAcquire() 办法分公正锁和非公正锁两套完成,首要做了两件事:

  1. 假如 AQS 当时 state0,测验获取锁资源。
  2. 假如 AQS 当时 state 不为 0,检查是否是可重入操作。

公正锁

protected final boolean tryAcquire(int acquires) {
    // 获取当时线程
    final Thread current = Thread.currentThread();
    // 获取AQS当时state值
    int c = getState();
    // 判断state是否为0,为0则代表当时没有线程持有锁
    if (c == 0) {
        // 首要判断是否有线程在排队,假如有,tryAcquie()办法直接回来false
        // 假如没有,则测验获取锁资源
        if (!hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 假如state != 0,则代表有线程持有锁资源
    // 判断占有锁的线程是不是当时线程,假如是,则进行可重入操作
    else if (current == getExclusiveOwnerThread()) {
        // 可重入
        int nextc = c + acquires;
        // 检查锁重入是否超越最大值,二进制第一位表明符号 
        // 01111111 11111111 11111111 11111111
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

非公正锁

final boolean nonfairTryAcquire(int acquires) {
    // 获取当时线程
    final Thread current = Thread.currentThread();
    // 获取AQS当时state值
    int c = getState();
    // 假如state == 0,说明没有线程占用着当时的锁资源
    if (c == 0) {
        // CAS直接测验获取锁资源,直接抢锁,不论有没有线程在行列中
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        // 检查锁重入是否超越最大值,二进制第一位表明符号 
        // 01111111 11111111 11111111 11111111
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        // 修改state当时值
        setState(nextc);
        return true;
    }
    return false;
}

ReentrantLock 的 addWaiter 办法源码

private Node addWaiter(Node mode) {
    // 将当时线程封装为Node对象,mode为null,代表互斥锁
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    // pred指向tail
    Node pred = tail;
    if (pred != null) {
        // 当时线程Node节点的prev指向pred节点
        node.prev = pred;
        // 以CAS办法,测验将node节点变成tail
        if (compareAndSetTail(pred, node)) {
            // 将pred的next指向node
            pred.next = node;
            return node;
        }
    }
    // 假如上述办法,CAS操作失利,导致加入到AQS结尾失利,就根据enq的办法添加到AQS行列
    enq(node);
    return node;
}

tryAcquire() 办法获取锁资源失利之后,首要创建当时线程的 Node 节点,之后将该节点添加到行列尾部。

private Node enq(final Node node) {
    // 死循环,直到刺进成功
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            //假如尾节点为null,说明同步行列还未初始化,则CAS操作新建头节点
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            // 将node的prev指向当时的tail节点
            node.prev = t;
            // CAS测验将node变成tail节点
            if (compareAndSetTail(t, node)) {
                // 将之前尾节点的next指向要刺进的节点
                t.next = node;
                return t;
            }
        }
    }
}

ReentrantLock 的 acquirdQueued 办法源码

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            // 获取node的前一个节点
            final Node p = node.predecessor();
            // 假如前一个节点为head并测验获取锁资源
            if (p == head && tryAcquire(arg)) {
                // 测验获取锁资源成功,将node节点设置为头节点,thread和prev属性置位null
                setHead(node);
                // 将之前的头节点的next指向null,帮助快速GC
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            // 假如前一个节点不是head或者获取锁资源失利
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
// 保证上一个节点的状况是正确的
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        return true;
    if (ws > 0) {
        // 循环往前找,找到一个状况小于等于0的节点
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        // 假如不是-1,可是小于等于0,将状况修改为-1
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

acquireQueued 办法会检查当时排队的 Node 的前一个节点是不是 head,假如是,测验获取锁资源。假如不是或者获取锁资源失利,那么就测验将当时 Node 的线程挂起。

在挂起线程前,需求确认当时节点的上一个节点的状况是小于等于 0

假如为 1,代表是取消的节点,不能挂起

假如为 -1,代表挂起当时线程

假如为 -2-3,需求将状况改为 -1 之后,才干挂起当时线程

ReentrantLock 的 unlock 办法源码

public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    // 中心开释锁办法
    if (tryRelease(arg)) {
        Node h = head;
        // 假如头节点不为null,并且头节点的状况不为0,唤醒排队的线程
        if (h != null && h.waitStatus != 0)
            // 唤醒线程
            unparkSuccessor(h);
        return true;
    }
    return false;
}
private void unparkSuccessor(Node node) {
    // 获取头节点状况
    int ws = node.waitStatus;
    // 假如头节点状况小于0,换为0
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);
    // 拿到当时节点的next
    Node s = node.next;
    // 假如s == null ,或者s的状况为1
    if (s == null || s.waitStatus > 0) {
        // next节点不需求唤醒,需求唤醒next的next
        s = null;
        // 从尾部往前找,找到状况正常的节点。(小于等于0代表正常状况)
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    // 通过循环的获取,假如拿到状况正常的节点,并且不为null
    if (s != null)
        // 线程唤醒
        LockSupport.unpark(s.thread);
}
// 中心的开释锁资源办法
protected final boolean tryRelease(int releases) {
    // state - 1
    int c = getState() - releases;
    // 假如开释锁的线程不是占用锁的线程,抛异常
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    // 是否成功的将锁资源开释 
    boolean free = false;
    if (c == 0) {
        // 假如state = 0,代表成功开释锁资源
        free = true;
        setExclusiveOwnerThread(null);
    }
    // 设置state值
    setState(c);
    return free;
}