ReentrantLock底层是通过在类的内部定义抽象静态内部类,其中对其中一些上锁和解锁方法进行实现或重写。ReentrantLock真正的公平锁和非公平锁是定义了两个静态内部类实现了Sync进行操作,这也体现了满足设计模式的依赖倒置原则,对类进行抽象,面向抽象类和接口编程。接下来我会先分析一下Sync:
重要方法:
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;
}
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;
}
这里的代码可以看到定义了非公平锁的可重入锁的获取锁和释放锁。这里代码逻辑比较简单就不赘述了。
接下来我会分别分析一下公平锁和非公平锁的的执行流程。
公平锁:
FairSync上锁:
final void lock() {
//上锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//如果发现锁是上了的,开始获取,
acquire(1);
}
尝试获取,这时候开始获取锁进入方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
执行方法
tryAcquire(arg),因为以及重写了所以返回到非公平锁执行下述方法.
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
这里可以看到这个方法会执行Sync里面的非公平获取锁,因为ReentrantLock是重入锁,就需要看看他是不是重入锁重入的可以继续上锁,继续执行,否则就要被弹回加入等待队列。解锁就比较简单,直接调用Sync的tryRelease,一层一层的解。明白AQS的都比较清楚,我就不在这里解释了。
接下来我会分别分析一下公平锁的执行流程。
公平锁:
上锁:
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;
}
这是公平版本获取锁,这里我们可以看到公平版和非公平版本的区别在于!hasQueuedPredecessors()
这一段,因为有一个等待队列已经排好队了,现在来了一个线程,他会直接抢锁,但是它在抢锁时会查一下,如果等待队列最前面排对的是不是为空,并且排在最前面的不是我,那么他就抢锁失败,加入等待队列。
这里就是公平锁的逻辑,
到这里ReentrantLock的重要逻辑已经全部讲完,其他的都是AQS的代码了。
最后我会讲一下可重入的实现,因为ReentrantLock这个对象内部的锁都是通过再类的内部定义的静态内部类和抽象静态内部类实现,ReentrantLock这个类被类加载器加载时会将静态数据加载到JVM的方法区里,这个静态数据是被所有对象共享的,也就是说每一个ReentrantLock对象初始化后都会共享这些静态数据,这也相当了ReentrantLock所有对象使用的是一把锁,只要某个线程获取了锁,可以一直进入这把锁。