ReentrantLock源码分析

ReentrantLock 是基于 AbstractQueuedSynchronizer(AQS)实现的可重入锁,它允许一个线程多次获取锁,并提供了公平和非公平两种锁获取模式。接下来,我们在之前 AQS源码分析基础上,详细分析 ReentrantLock 的源码和各个方法的实现。

1. 构造函数

ReentrantLock 提供了两种构造方式:默认的非公平锁,以及指定是否使用公平锁的构造方法。

public class ReentrantLock implements Lock, java.io.Serializable {
    private final Sync sync;

    // 默认构造函数,使用非公平锁
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    // 可选择公平锁或非公平锁
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
}

ReentrantLock 中的锁逻辑都由内部类 Sync 及其两个子类 FairSyncNonfairSync 来完成。

  • NonfairSync:非公平锁,允许线程插队。
  • FairSync:公平锁,严格遵守先到先得原则。

2. Sync 内部类

Sync 继承自 AQS,所有锁的核心功能都在这个类中。Sync 抽象类定义了几个用于实现锁的基础方法,这些方法被 FairSyncNonfairSync 实现。

abstract static class Sync extends AbstractQueuedSynchronizer {
    abstract void lock();  // 抽象的锁方法,由子类实现

    // 判断锁是否被当前线程持有
    final boolean isHeldExclusively() {
        return getExclusiveOwnerThread() == Thread.currentThread();
    }

    // 获取锁的重入次数
    final int getHoldCount() {
        return isHeldExclusively() ? getState() : 0;
    }

    // 判断锁是否被持有
    final boolean isLocked() {
        return getState() != 0;
    }
}

3. 非公平锁 NonfairSync

在非公平锁中,线程获取锁时不会关心排队情况,当前线程可以直接尝试获取锁,插队竞争锁资源。

static final class NonfairSync extends Sync {
    final void lock() {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
        } else {
            acquire(1);  // 调用AQS的acquire()方法
        }
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }

    final boolean nonfairTryAcquire(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;
        }
        return false;
    }
}
  • lock():首先使用 CAS(compareAndSetState)尝试直接获取锁。如果当前 state 为 0,表示锁未被持有,可以直接获取锁;如果锁已被持有,则调用 acquire(1),进入 AQS 的队列等待机制。

  • tryAcquire(int):尝试获取锁。如果锁未被持有(state == 0),则通过 CAS 操作尝试获取锁;如果当前线程已经持有锁,则增加重入次数。

4. 公平锁 FairSync

公平锁遵循严格的先到先得原则,线程会按照进入队列的顺序获取锁。

static final class FairSync extends Sync {
    final void lock() {
        acquire(1);  // 直接调用AQS的acquire()
    }

    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            // 公平锁:只有队列中没有其他线程时才获取锁
            if (!hasQueuedPredecessors() && 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;
        }
        return false;
    }
}
  • lock():直接调用 acquire(1),进入 AQS 的锁获取流程。
  • tryAcquire(int):如果 state == 0(锁未被占用),则会调用 hasQueuedPredecessors() 来判断当前线程是否是队列中的第一个。如果是第一个,才允许获取锁,确保公平性。

5. unlock()

unlock() 方法用来释放锁,释放锁时调用 AQS 的 release() 方法。

public void unlock() {
    sync.release(1);
}
5.1 release(int arg)
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
  • 调用 tryRelease(arg) 方法尝试释放锁。
  • 如果释放成功(返回 true),唤醒同步队列中的下一个等待线程。
5.2 tryRelease(int arg)
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}
  • tryRelease 方法会减少 state 值,表示锁的重入次数减少。如果 state 减为 0,表示当前线程完全释放了锁,并将持有锁的线程设置为 null

6. tryLock()

tryLock() 是非阻塞的锁获取方法,直接尝试获取锁并返回结果。

public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}
  • 非阻塞地调用 tryAcquire 方法尝试获取锁。

7. tryLock(long time, TimeUnit unit)

该方法允许在线程尝试获取锁时设置超时时间。如果在指定的时间内获取锁失败,则返回 false

public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(time));
}
  • tryAcquireNanosAQS 提供的限时等待锁的获取方法。
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout);
}
  • 首先尝试直接获取锁(调用 tryAcquire(arg)),如果失败则进入 doAcquireNanos(arg, nanosTimeout),进入同步队列等待,直到超时或被唤醒。

8. 条件变量 newCondition()

ReentrantLock 支持条件变量,通过 newCondition() 方法获取一个 ConditionObject,允许线程在获取锁的情况下等待,直到其他线程发出通知信号。

public Condition newCondition() {
    return sync.newCondition();
}

ConditionObject 是 AQS 的内部类,用于实现条件队列。线程调用 await() 方法进入等待队列,而调用 signal()signalAll() 方法则会唤醒等待队列中的线程。

public class ConditionObject implements Condition, java.io.Serializable {
    public final void await() throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        Node node = addConditionWaiter();
        int savedState = fullyRelease(node);
        int interruptMode = 0;
        while (!isOnSyncQueue(node)) {
            LockSupport.park(this);
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                break;
        }
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
    }

    public final void signal() {
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        Node first = firstWaiter;
        if (first != null)
            doSignal(first);
    }
}
  • await():线程进入条件等待,释放锁并挂起,直到被唤醒。
  • signal():唤醒条件队列中的一个线程。

9. getHoldCount()isLocked()

  • getHoldCount():返回当前线程持有锁的重入次数。调用 Sync 类的 getHoldCount() 方法。
public int getHoldCount() {
    return sync.getHoldCount();
}
  • isLocked():判断锁是否被占用。调用 Sync 类的 isLocked() 方法。
public boolean isLocked() {
    return sync.isLocked();
}

总结

ReentrantLock 基于 AQS 实现,提供了可重入锁机制,同时支持公平锁和非公平锁。ReentrantLock 主要依赖于内部类 Sync 来实现锁的具体逻辑,其中:

  • 非公平锁 允许线程插队,直接抢占锁资源;
  • 公平锁 遵循先到先得,保证锁的获取顺序。

ReentrantLock 还提供了 tryLock() 方法用于非阻塞获取锁,newCondition() 方法提供条件变量支持,使得它可以处理复杂的并发场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

愤怒的代码

如果您有受益,欢迎打赏博主😊

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

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

打赏作者

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

抵扣说明:

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

余额充值