ReentrantLock加锁、解锁源码解读

一、ReentrantLock类继承关系

二、方法

1、加锁:lock()

首先看一下方法调用线路图,RenntrantLock默认是非公平锁。

1、公平锁

final void lock() {
    // 调用AQS的acquire()
    acquire(1);
}

// 排它模式下,尝试获得锁
public final void acquire(int arg) {
    // tryAcquire 方法是需要实现类去实现的,实现思路一般都是 cas 给 state 赋值来决定是否能获得锁
    if (!tryAcquire(arg) &&
        // addWaiter 入参代表是排他模式
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

protected final boolean tryAcquire(int acquires) {
    		// 获取当前线程
            final Thread current = Thread.currentThread();
    		// 获取锁的状态,如果不为0,则说明锁别人持有
            int c = getState();
    		// 没人获得锁
            if (c == 0) {
                // hasQueuedPredecessors 是实现公平的关键
                // 会判断当前线程是不是队列中头结点的下一个节点(头节点是释放锁的节点)
                // 如果是(返回false),条件符合,可获得锁
                // 如果不是(返回true),则继续等待
                // compareAndSetState(0, acquires)自旋判断,如果锁的计数器不是0
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
    		// 如果当前线程不是线程持有者,则返回false
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    // 溢出检查
                    throw new Error("Maximum lock count exceeded");
                // 设置锁计数器值
                setState(nextc);
                return true;
            }
            return false;
        }

2、非公平锁

1、lock()
final void lock() {
    // CAS设置状态值
    if (compareAndSetState(0, 1))
        // CAS成功,将当前线程设置成获得锁的线程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // 调用AQS的acquire(),再次尝试获得锁
        // 失败会进入同步队列中
        acquire(1);
}

2、tryAcquire()
// 直接使用的是 Sync.nonfairTryAcquire 方法 
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}
3、nonfairTryAcquire()

​ 此方法与公平锁的差别主要是此处并不会去队列中判断自己是不是最早请求该锁的线程,可以理解是现实生活中的插队。

final boolean nonfairTryAcquire(int acquires) {
            
    final Thread current = Thread.currentThread();
    // 获取同步器的状态      
    int c = getState();
    // 状态为0的话,说明同步器的锁没有人持有        
    if (c == 0) {
        // 尝试CAS获得该锁,将AQS的状态从0设置为1
        if (compareAndSetState(0, acquires)) {
            // 设置当前线程为线程锁持有者        
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 锁已经被人持有,需要判断当前线程是不是锁的持有者;是的话,则状态值+1        
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        // 判断是否溢出了        
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    // 抢锁失败,放入AQS阻塞队列
    return false;
}

2、释放锁:unlock()

unlock 释放锁的方法,底层调用的是 Sync 同步器的 release 方法,release 是 AQS 的方法,分成两步:

  1. 调用Sync类的release方法,释放不成功返回false,调用步骤2
  2. 释放成功后,从同步队列中唤醒头结点的下一个节点,让其竞争锁
protected final boolean tryRelease(int releases) {        
    int c = getState() - releases;
    // 如果不是线程持有者释放锁会抛出异常        
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 如果同步器状态为为0,则清空锁持有线程        
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    // c不是0,当前线程已经拥有这个锁,即可重入锁,将重入次数-1.
    setState(c);
    return free;
}

tryRelease()方法是公平锁与非公平锁公用的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值