可重入鎖基本原理
阿新 • • 發佈:2020-11-30
轉自:http://www.jianshu.com/p/007bd7029faf
簡單鎖
在講述簡單鎖的實現之前,我們先來看一個鎖的應用例子:
public class Counter{
private Lock lock = new Lock();
private int count = 0;
public int inc(){
lock.lock();
this.count++;
lock.unlock();
return count;
}
}
上面的程式中,由於this.count++
這一操作分多步執行,在多執行緒環境中可能出現結果不符合預期的情況,這段程式碼稱之為臨界區,所以需要使用lock來保證其原子性。
Lock的實現:
public class Lock{
private boolean isLocked = false;
public synchronized void lock() throws InterruptedException{
while(isLocked){ //不用if,而用while,是為了防止假喚醒
wait();
}
isLocked = true;
}
public synchronized void unlock(){
isLocked = false;
notify();
}
}
說明:當isLocked為true時,呼叫lock()的執行緒在wait()阻塞。為防止該執行緒虛假喚醒,程式會重新去檢查isLocked條件。如果isLocked為false,當前執行緒會退出while(isLocked)迴圈,並將isLocked設回true,讓其它正在呼叫lock()方法的執行緒能夠在Lock例項上加鎖。當執行緒完成了臨界區中的程式碼,就會呼叫unlock()。執行unlock()會重新將isLocked設定為false,並且喚醒其中一個處於等待狀態的執行緒。
鎖的可重入性
同樣,先舉例來說明鎖的可重入性:
public class UnReentrant{
Lock lock = new Lock();
public void outer(){
lock.lock();
inner();
lock.unlock();
}
public void inner(){
lock.lock();
//do something
lock.unlock();
}
}
outer中呼叫了inner,outer先鎖住了lock,這樣inner就不能再獲取lock。其實呼叫outer的執行緒已經獲取了lock鎖,但是不能在inner中重複利用已經獲取的鎖資源,這種鎖即稱之為不可重入。通常也稱為自旋鎖。相對來說,可重入就意味著:執行緒可以進入任何一個它已經擁有的鎖所同步著的程式碼塊。
可重入鎖的基本原理
我們在上面的Lock基礎上作一些修改:
public class Lock{
boolean isLocked = false;
Thread lockedBy = null;
int lockedCount = 0;
public synchronized void lock()
throws InterruptedException{
Thread callingThread = Thread.currentThread();
while(isLocked && lockedBy != callingThread){
wait();
}
isLocked = true;
lockedCount++;
lockedBy = callingThread;
}
public synchronized void unlock(){
if(Thread.curentThread() == this.lockedBy){
lockedCount--;
if(lockedCount == 0){
isLocked = false;
notify();
}
}
}
}
- lockBy:儲存已經獲得鎖例項的執行緒,在lock()判斷呼叫lock的執行緒是否已經獲得當前鎖例項,如果已經獲得鎖,則直接跳過while,無需等待。
- lockCount:記錄同一個執行緒重複對一個鎖物件加鎖的次數。否則,一次unlock就會解除所有鎖,即使這個鎖例項已經加鎖多次了。