ReentrantLock实现可重入性是通过维护一个持有锁的线程和一个锁计数器来实现的。当一个线程第一次获取锁时,计数器加1,表示锁被该线程持有。在进入临界区后,如果该线程再次尝试获取锁,此时计数器会增加,而不需要等待其他线程释放锁。
当线程退出临界区后,计数器减1。只有当计数器降为0时,表示所有的锁都已释放,其他线程才能获得锁。可重入性的实现的关键在于被持有的锁与持有锁的线程之间的关联。
示例代码如下所示:
```java
class ReentrantLock {
private boolean isLocked = false; // 锁标志
private Thread lockedBy = null; // 持有锁的线程
private int lockCount = 0; // 锁计数器
// 获取锁
public synchronized void lock() {
Thread currentThread = Thread.currentThread();
while (isLocked && lockedBy != currentThread) {
// 锁已被其他线程持有,且不是当前线程
try {
wait();
} catch (InterruptedException e) {
// 处理异常
}
}
isLocked = true;
lockCount++;
lockedBy = currentThread;
}
// 释放锁
public synchronized void unlock() {
if (Thread.currentThread() == lockedBy) {
lockCount--;
if (lockCount == 0) {
isLocked = false;
lockedBy = null;
notify();
}
}
}
}
```
在上述示例中,当线程调用lock()方法获取锁时,会进行如下判断:
1. 如果锁已被其他线程持有,且不是当前线程,则当前线程进入等待状态;
2. 如果锁未被其他线程持有,或者锁被当前线程持有,则锁标志(isLocked)被设置为true,锁计数器(lockCount)加1,持有锁的线程(lockedBy)设为当前线程。
在unlock()方法中,判断当前线程是否持有锁,如果是,则将锁计数器减1,如果计数器降为0表示锁已完全释放,锁标志(isLocked)被设置为false,持有锁的线程(lockedBy)设为null,并通知其他等待的线程可以尝试获取锁。
这样,通过锁计数器的增减和持有锁的线程的标识,ReentrantLock实现了可重入性,即同一个线程可以多次获取同一把锁而不会出现死锁的情况。