问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

ReentrantLock非公平锁原理详解

创作时间:
作者:
@小白创作中心

ReentrantLock非公平锁原理详解

引用
CSDN
1.
https://blog.csdn.net/m0_62645012/article/details/138963528

ReentrantLock是非阻塞锁的一种实现,它提供了比synchronized更灵活的锁获取方式。本文将深入探讨ReentrantLock的非公平锁实现原理,包括加锁和解锁的具体过程。

ReentrantLock有两种锁:公平锁和非公平锁。从构造器来看,ReentrantLock默认实现是非公平锁。

1. 非公平锁原理

加锁过程

当没有竞争时,非公平锁会直接将exclusiveOwnerThread设置为当前线程,并将state设置为1。

当有多个线程竞争锁时,线程会通过acquire方法尝试获取锁:

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

如果CAS操作失败,线程会进入等待队列:

private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}

线程进入acquireQueued方法后,会不断尝试获取锁:

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null;
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

如果线程在队列中,会通过shouldParkAfterFailedAcquire方法检查是否需要阻塞:

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        return true;
    if (ws > 0) {
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

如果需要阻塞,线程会通过parkAndCheckInterrupt方法进入等待状态:

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

解锁过程

当持有锁的线程释放锁时,会调用release方法:

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

如果释放成功,会唤醒等待队列中的下一个线程:

private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 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)
        LockSupport.unpark(s.thread);
}

注意事项

  • 是否需要唤醒线程是由当前节点的前驱节点的waitStatus决定的,而不是本节点的waitStatus
  • 非公平锁允许新来的线程插队,这可能会导致某些线程长时间等待。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号