ReentrantLock加锁源码解析

本文详细解析了公平锁的加锁过程,包括竞争锁、加入等待队列和阻塞等待的逻辑。首先介绍了如何通过CAS操作在没有线程等待或当前线程已持有锁时抢占锁。接着讨论了当有线程等待时,如何根据公平原则决定是否允许当前线程加锁。然后,文章详细阐述了等待队列的初始化、添加新节点以及阻塞等待的实现细节,包括如何避免空指针异常和线程的阻塞与唤醒。最后总结了公平锁加锁的完整流程。
摘要由CSDN通过智能技术生成

1.竞争锁 我们先从公平锁入手

public void lock() {
    // sync的实例是new FairSync()
    sync.acquire(1);
}
// 加锁的代码就是这几行
public final void acquire(int arg) {
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
复制代码

上述代码可以拆分成以下几段:

// 竞争锁
tryAcquire(arg)
// 加入等待队列
addWaiter(Node.EXCLUSIVE)
// 阻塞等待
acquireQueued(node, arg)
复制代码
  • 竞争锁
protected final boolean tryAcquire(int acquires) {
    // 获取当前线程
    final Thread current = Thread.currentThread();
    // 获取当前state状态
    int c = getState();
    // 如果当前state是没有任何线程抢占的话
    if (c == 0) {
        // 如果等待队列中有任何一个等待的节点,都不会抢占锁
        if (!hasQueuedPredecessors() &&
            // CAS抢占锁成功
            compareAndSetState(0, acquires)) {
            // 抢占成功后,标记当前线程已经抢占到锁了。
            setExclusiveOwnerThread(current);
            // 返回加锁成功
            return true;
        }
    }
    // 如果是同一个线程重复加锁的情况下
    else if (current == getExclusiveOwnerThread()) {
        // 在这种情况下,只是简单地操作state
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        // 因为当前线程已经加锁成功了,再次加锁的话,直接在state上增加加锁次数即可。
        setState(nextc);
        // 返回加锁成功
        return true;
    }
    // 如果已经有别的线程加锁了,或者还有很多线程在排队等待,那么返回false加锁失败。
    return false;
}
复制代码

上述代码分几部分:

  1. 如果当前state=0,也就是没有任何线程抢占锁的情况下
    1.1: 没有等待队列的情况下,可以CAS抢占锁
    1.2: 有等待队列的话,该队列中第一个等待节点不是当前线程,不可以抢占锁,因为这是公平锁。

如果当前等待队列中还有任意节点,并且当前节点中的线程不是当前线程,说明有其他线程处于等待过程中,那么当前线程就应该乖乖排队去。

1.3: 有等待队列,并且当前第一个等待节点就是当前线程,可以抢占锁。这种情况会出现在线程刚从阻塞中被唤醒的时候。

  1. 假如当前线程是被刚刚唤醒的,并且它处于等待队列中的第一个等待的位置,那么这个时候是可以去抢占锁的。
  2. 如果已经抢占了锁的线程就是当前线程。这种情况我们叫做重入。
    示例如下:
ReentrantLock lock = new ReentrantLock();
try {
    // 加锁
    lock.lock();
    // 执行业务逻辑
    System.out.println("获取的锁");
    try {
        // 再次获取锁
        lock.lock();
        // 执行业务逻辑
        System.out.println("再次获取的锁");
    } finally {
        // 解锁
        lock.unlock();
    }
} finally {
    // 解锁
    lock.unlock();
}
复制代码

小结一下: 

  1. 如果当前锁未被抢占࿰
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值