在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,則表示有線程比當前線程更早地請求獲取鎖,因此需要等待前驅節點下次呢很難過獲取並釋放鎖之後才能繼續獲取鎖。