ReentrantLock即重入鎖,支持一個線程對資源重複加鎖。除此之外,該鎖還支持獲取鎖時公平性和非公平性選擇。
前面我的博客中實現的Mutex不支持重入。Synchronized關鍵字隱式支持重進入。
對於ReentrantLock,已經獲取到鎖的線程再次調用lock方法獲取鎖不被阻塞。
公平地獲取鎖就是等待時間最長地線程優先獲取鎖,鎖的獲取是順序的。
下面是公平獲取鎖和非公平獲取鎖的代碼
public static class Sync extends AbstractQueuedSynchronizer
{
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 exceed");
}
setState(nextc);
return true;
}
return false;
}
protected final boolean nofairTryAcquire(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)
{
throw new Error("Maximum lock count exceed");
}
setState(nextc);
return true;
}
return false;
}
protected final boolean tryRelease(int releases)
{
for(;;)
{
int current=getState();
int c=current-releases;
if(Thread.currentThread()!=getExclusiveOwnerThread())
{
throw new IllegalMonitorStateException();
}
boolean free=false;
if(c==0)
{//當狀態值減爲0才表示真正釋放了鎖,這時才能返回true
free=true;
setExclusiveOwnerThread(null);
}
if(compareAndSetState(current,c))
return free;
}
}
(1)線程再次獲取鎖。鎖需要識別獲取到鎖的線程是否爲當前佔據鎖的線程,如果是就再次成功獲取,否則就阻塞。鎖的獲取需要計數自增
(2)鎖的最終釋放。線程重複 n 次獲取了鎖,隨後在第 n 次釋放該鎖後,其他線程才能獲取到該鎖。鎖的釋放需要計數自減,當計數爲0表示鎖已經成功釋放,並返回true,否則返回false