面试官:有了解过ReentrantLock的底层实现吗?说说看("面试必问:深入解析ReentrantLock底层实现原理")
原创
一、ReentrantLock简介
ReentrantLock是Java中提供的一种显示锁机制,它实现了Lock接口,提供了比synchronized关键字更充裕的功能,如可中断的锁获取、尝试非阻塞地获取锁、赞成公平锁等。ReentrantLock的实现原理是基于Java的AQS(AbstractQueuedSynchronizer)框架。
二、AQS框架
AQS是Java并发包中一个非常核心的组件,它为ReentrantLock、CountDownLatch、Semaphore等并发工具提供了底层赞成。AQS框架的核心原理是利用了CLH队列(Craig, Landin, and Hagersten queue)来实现同步。
三、ReentrantLock的底层实现
ReentrantLock底层实现首要分为两部分:Sync类和NonfairSync类(非公平锁)和FairSync类(公平锁)。
3.1 Sync类
Sync类是ReentrantLock的内部类,它继承了AQS。Sync类提供了ReentrantLock的基本操作,如lock、unlock等。
public abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6476155730509392570L;
protected Sync() {
}
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) {
throw new Error("Maximum lock count exceeded");
}
setState(nextc);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (c < 0) {
throw new IllegalMonitorStateException();
}
if (c == 0) {
setExclusiveOwnerThread(null);
return true;
}
return false;
}
}
3.2 NonfairSync类
NonfairSync类是Sync的子类,它实现了非公平锁的获取和释放操作。在NonfairSync中,lock方法直接调用AQS的acquire方法。
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -871948314811505487L;
NonfairSync() {
}
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
3.3 FairSync类
FairSync类也是Sync的子类,它实现了公平锁的获取和释放操作。在FairSync中,lock方法调用了AQS的acquire方法,但tryAcquire方法会有所不同。
static final class FairSync extends Sync {
private static final long serialVersionUID = -7284743614705905476L;
FairSync() {
}
final void lock() {
acquire(1);
}
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;
}
}
四、ReentrantLock的获取和释放锁流程
下面我们来分析一下ReentrantLock获取和释放锁的流程。
4.1 获取锁(lock方法)
当线程调用ReentrantLock的lock方法时,实际上会调用Sync类的acquire方法。acquire方法会尝试通过tryAcquire方法获取锁,如果获取未果,则会将当前线程加入到AQS的等待队列中。
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
4.2 释放锁(unlock方法)
当线程调用ReentrantLock的unlock方法时,实际上会调用Sync类的release方法。release方法会尝试通过tryRelease方法释放锁,如果释放胜利,则会唤醒AQS队列中的下一个线程。
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
五、总结
ReentrantLock的实现原理是基于Java的AQS框架。通过Sync类和其子类NonfairSync和FairSync,ReentrantLock提供了公平锁和非公平锁的实现。获取锁的过程是通过tryAcquire方法尝试获取锁,如果未果则加入等待队列;释放锁的过程是通过tryRelease方法释放锁,并唤醒等待队列中的下一个线程。通过深入了解ReentrantLock的底层实现,我们可以更好地懂得并发编程中的锁机制,以及怎样高效地使用ReentrantLock来保证线程可靠。