在java中,一般的锁实现都要借助队列同步器AbstractQueuedSynchronizer
,继承它并重写其指定的方法,随后调用同步器提供的模板方法,模板方法最终会再调用到自己重写的方法。tryAcquire(int acquires)
就是其中的一个抽象方法,需要重写。
ReentrantLock公平锁与非公平锁的实现原理区别就是抽象方法tryAcquire
的实现不同。公平锁的同步器tryAcquire
方法如下:
//公平锁
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;
}
}
非公平锁的同步器tryAcquire
方法如下
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
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;
}
总结:公平锁与非公平锁相比,唯一不同的位置为判断条件多了hasQueuedPredecessors
方法,即加入了同步队列的当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早地请求获取锁,因此需要等待前驱节点下次呢很难过获取并释放锁之后才能继续获取锁。