ReentrantLock是如何实现公平锁的?

ReentrantLock 通过内部的队列管理机制来实现公平锁。公平锁意味着线程会按照请求锁的顺序获取锁,避免了“饥饿”现象。下面是 ReentrantLock 实现公平锁的具体方式:

1. 公平锁的定义

在公平模式下,ReentrantLock 会将等待获取锁的线程放入一个 FIFO(先进先出)队列中。当当前锁被释放时,会优先唤醒等待队列中最先请求的线程,确保线程获取锁的顺序是公平的。

2. 实现机制

a. 继承 AQS

ReentrantLock 的公平锁实现是通过继承 AQS 的一个子类 FairSync 来完成的。FairSync 重写了 AQS 中的一些关键方法,以实现公平策略。

b. 重写 tryAcquire 方法

FairSync 中,tryAcquire(int acquires) 方法会检查当前锁是否被其他线程占用。如果锁未被占用,线程可以直接获取锁。如果锁被占用,公平锁会检查等待队列中是否有线程在等待:

static final class FairSync extends Sync {
    // 重写 tryAcquire 以实现公平性
    @Override
    protected boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        // 如果锁未被占用,尝试获取锁
        if (c == 0) {
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        } else if (current == getExclusiveOwnerThread()) { // 如果当前线程已持有锁,重入
            int nextc = c + acquires; // 增加锁计数
            if (nextc < 0) // 检查计数溢出
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        // 此处实现公平性
        // 将当前线程加入到等待队列中(如果未持有锁的情况下)
        if (!hasQueuedPredecessors()) {
            if (compareAndSetState(0, acquires)) { // 尝试获取锁
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        return false;
    }
}
  • hasQueuedPredecessors() 方法是判断当前线程是否有前驱线程在等待队列中。如果有其他线程在等待,那么当前线程必须等待,直到前面的线程获取锁后才能尝试获取。
c. 线程等待队列的管理

当线程请求锁失败并且 hasQueuedPredecessors() 返回 true 时,线程会被放入 AQS 提供的等待队列。这样,后续的线程请求将会被排列在队列中,确保按照请求的顺序:

  • 当锁被释放时,AQS 会自动唤醒队列中的第一个线程,并使其能够尝试获取锁。

3. 获取锁的方法

  • lock() 方法会调用 tryAcquire(1) 来获取锁。由于 FairSync 中的实现,后续调用 lock() 的线程会在等待队列中排队,直到锁被释放。

4. 总结

ReentrantLock 通过继承 AQS 的 FairSync 类,实现了公平锁的特性。线程请求锁的顺序是FIFO的,从而避免了潜在的饥饿现象。公平锁确保了线程的公平性,但可能导致系统性能的下降,因为可能会出现更高的上下文切换和调度延迟。

如果你有其他问题或需要进一步探讨,请随时在评论区留言!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java奋斗者

听说打赏我的人再也不会有BUG

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值