ReentrantLock是JDK提供的一个可重入互斥锁,所谓可重入就是同一个锁允许被已经获得该锁的线程重新获得。可重入锁的好处可以在递归算法中使用锁,不可重入锁则导致无法在递归算法中使用锁。因为第二次递归时由于第一次递归已经占有锁,而导致死锁。
1.默认构造函数是new一个非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
2.因为是独占式锁,需要实现AQS的tryAcquire函数和tryRelease函数
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) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
- 先得到当前线程
- 查询当前state值,如果为0则说明当前锁还未被其他线程获取,则尝试CAS获得锁,成功则把占有锁的线程设置为当前线程,返回true。失败返回false。
- 如果state不为0则说明该锁已经被其他线程获取,则检查获得锁的线程是否是当前线程以实现可重入特性,如果是,则更新state的值,并返回true。此处更新不需要CAS,因为只有当前线程可以操作state。
- 其他情况返回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;
}
- 首先得到释放之后的状态值c
- 检查当前释放锁的线程,如果不是已占有锁的线程则抛出异常,因为ReentrantLock是独占式锁,释放锁的线程一定是占有锁的线程
- 如果c是等于0的,说明获取锁的所有函数都已经返回,则锁释放成功
- 如果c不等于0,说明只是部分递归的函数返回,部分递归函数还未返回,则释放失败,锁依然被占有
3.ReentrantLock的两个主要方法lock和unlock源码了解一下:
public void lock() {
sync.lock();
}
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
该函数首先直接尝试CAS操作,成功则设置当前函数为占有锁的函数,返回,失败则调用acquire函数。acquire函数为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;
}
调用tryRelease函数释放锁
网友评论