ReentrantLock 是 Java 中的一个高级同步机制,它提供了比传统的 synchronized 方法和语句更灵活的锁定操作。ReentrantLock 实现了 Lock 接口,并且完全依赖于 AbstractQueuedSynchronizer (AQS) 的扩展来实现其同步行为。
ReentrantLock 特性
- 可重入: 同一个线程可以多次获得同一把锁。
- 公平性: 可以设置锁的公平性。公平锁意味着等待时间最长的线程会首先获得锁。
- 锁绑定多个条件: 可以绑定多个 Condition实例,实现线程间更精细的同步。
ReentrantLock 实现原理
ReentrantLock 在内部通过其静态内部类 Sync 来使用 AQS。Sync 是一个抽象类,它扩展了 AQS,并提供了所有锁操作的基础。Sync 有两个子类 FairSync 和 NonfairSync,分别提供公平和非公平锁的操作。公平和非公平锁的主要区别在于是否考虑线程等待的顺序。
以下是 ReentrantLock 中的一些关键方法的内部实现概念:
lock()
非公平锁 (NonfairSync) 和公平锁 (FairSync) 的 lock() 方法略有不同。在非公平锁中,调用 lock() 会直接尝试获取锁,如果成功则立即返回,如果失败则进入同步队列等待。对于公平锁,当一个线程调用 lock(),它会首先检查是否有其他线程正等待获取锁,即使当前锁是可用的,也会保证按照等待的先后顺序来获取锁。
public void lock() {sync.lock();
}
unlock()
释放锁的操作是通过调用 AQS 的 tryRelease(int arg) 方法来实现的。tryRelease(int arg) 将会在成功释放锁时返回 true,通知后继节点的线程尝试获取锁。
public void unlock() {sync.release(1);
}
tryLock()
该方法尝试获取锁,如果锁立即可用(即不存在争用),则成功获取并返回 true;如果锁不可用,则返回 false,此方法不会等待。
public boolean tryLock() {return sync.nonfairTryAcquire(1);
}
lockInterruptibly()
该方法与 lock() 相似,但它允许在等待锁的过程中响应中断。如果当前线程在进入同步队列或者已经在队列中等待时被中断,它会抛出 InterruptedException 并退出锁申请。
public void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);
}
newCondition()
ReentrantLock 提供了自己的 Condition 实现,这允许与内部锁状态进行更紧密的协作。
public Condition newCondition() {return sync.newCondition();
}
AQS 在 ReentrantLock 中的使用
ReentrantLock 在 AQS 的基础上定义了资源(锁)的获取和释放方式:
- 获取锁: AQS 通过 tryAcquire(int arg)方法的覆写来定义锁的获取行为。如果当前状态为0,说明锁未被持有,试图设置状态为1表示锁被当前线程独占。
- 释放锁: AQS 通过 tryRelease(int arg)方法的覆写来定义锁的释放行为。它尝试将状态设置回0,以便其他线程可以获取锁。
这些重写的方法会利用 AQS 提供的原子性状态操作方法,如 getState(), setState(int newState), compareAndSetState(int expect, int update) 等来管理同步状态。
ReentrantLock 的源码示例
下面是一个简化版的 ReentrantLock 实现,突出显示了 AQS 在其中的应用:
public class ReentrantLock implements Lock, java.io.Serializable {private final Sync sync;abstract static class Sync extends AbstractQueuedSynchronizer {abstract void lock();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) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}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;}// 省略其他方法...}static final class NonfairSync extends Sync {final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}// 省略其他方法...}static final class FairSync extends Sync {final void lock() {acquire(1);}// 省略其他方法...}// 构造函数 - 创建公平或非公平的锁public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}// 实现Lock接口的方法public void lock() {sync.lock();}// 省略其他方法...
}
在上述示例中,ReentrantLock 包含两个 Sync 的内部类,FairSync 和 NonfairSync。lock() 方法调用 acquire(1),它是 AQS 中的方法,负责管理队列中线程的排队和阻塞行为。tryAcquire(int arg) 和 tryRelease(int arg) 方法在 Sync 类中被定义,它们通过 AQS 提供的方法来操作同步状态。
通过这种方式,ReentrantLock 利用 AQS 的基础设施来实现锁的功能,并提供了丰富的同步操作。