2020年3月28日 作者 zeroheart

公平锁和非公平锁的实现

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()方法,主要判断上述的双向链表,如果队列为空或者队列不为空,当前线程为第一个等待的线程,那么获得锁。