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 的基础设施来实现锁的功能,并提供了丰富的同步操作。