我們最早接觸java線程鎖惦费,其實(shí)也就是syncronized和ReentrantLock,ReentrantLock作為L(zhǎng)ock的一個(gè)實(shí)現(xiàn)抢韭,其實(shí)構(gòu)造時(shí)薪贫,也分為公平鎖與非公平鎖之分。
先看源碼:
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
這一部分就是ReentrantLock的構(gòu)造方法刻恭,傳入的參數(shù)不同構(gòu)造的鎖類型就將不同瞧省。
下面先看看一下公平鎖的實(shí)現(xiàn),源碼如下:
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* 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) {
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;
}
}
然后再貼出非公平鎖的實(shí)現(xiàn)源碼:
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
先從概念上鳍贾,我的理解是:
公平鎖: 每個(gè)等待的線程首先他們獲取鎖的機(jī)會(huì)是公平的鞍匾,那么怎么保證他們是公平的呢?只能是根據(jù)申請(qǐng)鎖的順序來(lái)保證骑科,那順序又如何保證呢橡淑,必然是有一個(gè)類似隊(duì)列的數(shù)據(jù)結(jié)構(gòu)來(lái)序列化等待的線程。
非公平鎖:從字面意思上理解咆爽,每個(gè)等待的線程獲取鎖的機(jī)會(huì)是不公平的梁棠,那他們?nèi)绾潍@取鎖呢?顯然獲取鎖的時(shí)候就該八仙過(guò)海斗埂,各顯神通了符糊,必然會(huì)導(dǎo)致有些能力差的線程搶不到鎖。
帶著這些概念上的理解與思路我們開(kāi)始重讀源碼呛凶。先從non-fair locks 開(kāi)始男娄。
非公平鎖
我們來(lái)逐行分析:
1.首先是對(duì)象序列化時(shí)候的UID。
2.lock()是一個(gè)構(gòu)建鎖的方法,tryAcquire()是一個(gè)獲取鎖的方法沪伙。
3.先看lock()方法瓮顽,會(huì)先去執(zhí)行本地CAS算法,看看當(dāng)前鎖的狀態(tài)是不是0围橡,是0的話就改為1暖混,那么就給當(dāng)前線程排它的權(quán)限,也就是對(duì)當(dāng)前線程操作的資源加上了鎖翁授。如果CAS算法結(jié)果不成立拣播,然后會(huì)去獲取鎖。
- tryAcquire()嘗試獲取鎖方法收擦。
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
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;
}
如果當(dāng)前資源不在同步狀態(tài)贮配,compareAndSetState(0, acquires) CAS算法看狀態(tài), setExclusiveOwnerThread(current);設(shè)置當(dāng)前線程加鎖塞赂。如果當(dāng)前線程有鎖就更新鎖狀態(tài)泪勒。
公平鎖
與非公平鎖一樣,提供lock()與tryAcquire()方法宴猾,不一樣的是fair lock多了一個(gè)對(duì)等待線程隊(duì)列的判斷圆存,當(dāng)前線程是否處在最前。