2020年3月28日
公平锁和非公平锁的实现
ReentrantLock中,提供公平锁和非公平锁,通过构造函数ReentrantLock(boolean fair)实现。
具体情况是在内存中维护了一个双向链表,非公平情况下获取锁时,新加入的线程有优势,可以获得锁。代码段如下:
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//如果没有线程获取锁,则当前线程CAS获取锁。并设置自己为当前锁的独占线程
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
// 如果存在锁竞争,判断获取锁的线程是否是当前线程, 因为ReentrantLock是可重入锁,
//用state变量表示重入次数,即:使当前state+1;
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//如果不是当前线程,则不能获取同步状态
return false;
}
可以注意到只要线程获取锁,并且锁为空闲的情况下,直接得到锁了。而公平锁多了一个判断。!hasQueuedPredecessors()
if (c == 0) {
if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
}
hasQueuedPredecessors()方法,主要判断上述的双向链表,如果队列为空或者队列不为空,当前线程为第一个等待的线程,那么获得锁。