基礎(chǔ)
- 重入鎖:一個(gè)線(xiàn)程對(duì)同一個(gè)鎖資源可以重復(fù)獲?。ㄈ鐂ynchronized關(guān)鍵字)
- ReentrantLock是可重入鎖,并且支持獲取鎖時(shí)的公平與非公平選擇。
- ReentrantLock默認(rèn)為非公平鎖,這是出于性能考慮(對(duì)于非公平鎖,一個(gè)剛釋放鎖的線(xiàn)程很大概率可以再次獲得該鎖,而不用去排隊(duì),減少上下文切換次數(shù))。而公平鎖總是會(huì)讓你到同步隊(duì)列走一遭,即使你剛釋放了鎖,然后立馬請(qǐng)求鎖。即公平鎖的實(shí)現(xiàn)是以線(xiàn)程切換為代價(jià)的。
基本使用
ReentrantLock lock = new ReentrantLock();//非公平鎖
//ReentrantLock lock = new ReentrantLock(true);//公平鎖
lock.lock();
try{
//to do
}finally {
lock.unlock();
}
ReentrantLock的基本骨架
ReentrantLock implements Lock{
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {......};
static final class NonfairSync extends Sync {};//非公平鎖用這個(gè)同步器
static final class FairSync extends Sync {};//公平鎖用這個(gè)同步器
}
public ReentrantLock(boolean fair) {//選擇是公平鎖還是非公平鎖
sync = fair ? new FairSync() : new NonfairSync();
}
public ReentrantLock() {//默認(rèn)為非公平鎖
sync = new NonfairSync();
}
源碼角度分析其可重入性和公平性的實(shí)現(xiàn)
可重入特性實(shí)現(xiàn)(非公平鎖為例)
鎖的獲取
如果當(dāng)前同步狀態(tài)已經(jīng)被線(xiàn)程獲?。╯tate != 0),判斷當(dāng)前嘗試獲取同步狀態(tài)的線(xiàn)程是否是已經(jīng)獲取同步狀態(tài)的線(xiàn)程,如果是就代表當(dāng)前線(xiàn)程重入獲取鎖,將同步狀態(tài)的值增加(所以獲取鎖多少次,就應(yīng)該釋放鎖多少次),返回成功。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//可重入特性提現(xiàn)在這里
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;
}
鎖的釋放
因?yàn)橥綘顟B(tài)的獲取可能獲取了n次,所以應(yīng)該只有最后一次釋放之后才應(yīng)該返回true(線(xiàn)程已釋放鎖)。
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
公平性實(shí)現(xiàn)
用戶(hù)層面而言:鎖的獲取嚴(yán)格遵守FIFO模式
源碼角度來(lái)說(shuō):公平鎖的tryAcquire與非公平鎖不同之處在于---公平鎖如果判斷鎖空閑,還需要去判斷同步隊(duì)列中有沒(méi)有在排隊(duì)的(非公平鎖沒(méi)有這一步),如果有的話(huà)就去同步隊(duì)列中排隊(duì)。
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//公平鎖實(shí)現(xiàn)的關(guān)鍵
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;
}