天天看點

深入分析ReentrantLock公平鎖和非公平鎖的差別

在ReentrantLock中包含了公平鎖和非公平鎖兩種鎖,通過檢視源碼可以看到這兩種鎖都是繼承自Sync,而Sync又繼承自AbstractQueuedSynchronizer,而AbstractQueuedSynchronizer又繼承自AbstractOwnableSynchronizer,下面是類的繼承關系圖:

其中AbstractOwnableSynchronizer是提供了設定占用目前鎖的線程資訊的方法,主要的鎖的實作還是在AbstractQueuedSynchronizer中實作的,在AbstractQueuedSynchronizer中通過CLH隊列實作了多線程鎖的排隊使用,但是該隊列的實作并不能保證鎖的公平競争,但是在某些業務場景中會需要保證先到的線程先得到鎖,是以就有了公平鎖和非公平鎖的誕生。

通過分析ReentrantLock中的公平鎖和非公平鎖的實作,其中tryAcquire是公平鎖和非公平鎖實作的差別,下面的兩種類型的鎖的tryAcquire的實作,從中我們可以看出在公平鎖中,每一次的tryAcquire都會檢查CLH隊列中是否仍有前驅的元素,如果仍然有那麼繼續等待,通過這種方式來保證先來先服務的原則;而非公平鎖,首先是檢查并設定鎖的狀态,這種方式會出現即使隊列中有等待的線程,但是新的線程仍然會與排隊線程中的對頭線程競争(但是排隊的線程是先來先服務的),是以新的線程可能會搶占已經在排隊的線程的鎖,這樣就無法保證先來先服務,但是已經等待的線程們是仍然保證先來先服務的,是以總結一下公平鎖和非公平鎖的差別:

1、公平鎖能保證:老的線程排隊使用鎖,新線程仍然排隊使用鎖。

2、非公平鎖保證:老的線程排隊使用鎖;但是無法保證新線程搶占已經在排隊的線程的鎖。

公平鎖的tryAcquire

/**

* Fair version of tryAcquire. Don't grant access unless

* recursive call or no waiters or is first.

*/

protected final boolean tryAcquire(int acquires) {

final Thread current = Thread.currentThread();

int c = getState();

if (c == 0) {

// !hasQueuedPredecessors()保證了不論是新的線程還是已經排隊的線程都順序使用鎖

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;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

非公平鎖的

/**

* Performs non-fair tryLock. tryAcquire is implemented in

* subclasses, but both need nonfair try for trylock method.

final boolean nonfairTryAcquire(int acquires) {

// 新的線程可能搶占已經排隊的線程的鎖的使用權

if (compareAndSetState(0, acquires)) {

if (nextc < 0) // overflow

ReentrantLock和LockSupport

http://blog.47777205.com/

繼續閱讀