可重入鎖和不可重入鎖


不可重入鎖

先來設計一種鎖

public class Lock{
    private boolean isLocked = false;
    public synchronized void lock() throws InterruptedException{
        while(isLocked){    
            wait();//把當前線程wait
        }
        isLocked = true;
    }
    public synchronized void unlock(){
        isLocked = false;
        notify();
    }
}

這其實是個不可重入鎖,舉個例子

public class Count{
    Lock lock = new Lock();
    public void print(){
        lock.lock();
        doAdd();
        lock.unlock();
    }
    public void doAdd(){
        lock.lock();
        //do something
        lock.unlock();
    }
}

  當調用print()方法時,獲得了鎖,這時就無法再調用doAdd()方法,這時必須先釋放鎖才能調用,所以稱這種鎖為不可重入鎖,也叫自旋鎖。

可重入鎖

public class Lock{
    boolean isLocked = false;
    Thread  lockedBy = null;
    int lockedCount = 0;
    public synchronized void lock()
            throws InterruptedException{
        Thread thread = Thread.currentThread();
        while(isLocked && lockedBy != thread){
            wait();
        }
        isLocked = true;
        lockedCount++;
        lockedBy = thread;
    }
    public synchronized void unlock(){
        if(Thread.currentThread() == this.lockedBy){
            lockedCount--;
            if(lockedCount == 0){//獲得該鎖的那個線程,獲得了多少次該鎖(即調用了幾次lock方法,即重入了幾次),就得unlock幾次,即lockedCount=0,才會把那些wait(阻塞)的線程喚醒
                isLocked = false;
                notify();
            }
        }
    }
}

相對來說,可重入就意味着:一個線程可以進入任何一個 該線程 已經擁有的鎖所同步着的代碼塊

  第一個線程執行print()方法,得到了鎖,使lockedBy等於當前線程,也就是說,執行的這個方法的線程獲得了這個鎖,執行add()方法時,同樣要先獲得鎖(即調用lock.lock()),因不滿足while循環的條件isLocked(=true,因為該線程調用print()方法時就獲得該鎖了);但是這里與不可重入鎖的區別是有個lockedBy(即表示現在哪個線程持有鎖);因為調用add()方法的是和調用print()的是同一個線程,也就是不等待,繼續進行,將此時的lockedCount變量,也就是當前獲得鎖的數量加一,當釋放了所有的鎖(即得調用獲得鎖數量次數的unlock),才執行notify()。

  如果在執行這個方法時,有第二個線程想要執行這個方法,因為lockedBy不等於第二個線程,導致這個線程進入了循環,也就是等待(阻塞),不斷執行wait()方法。只有當第一個線程釋放了所有的鎖(即第一個線程調用了多少次lock()方法就得調用多少次unlock()方法釋放鎖),執行了notify()方法,第二個線程才得以跳出循環,繼續執行。

這就是可重入鎖的特點。

  可重入鎖與不可重入鎖對比,簡單來說就是:可重入鎖會多兩個屬性(1、獲得該鎖的線程;2、獲得該鎖的次數),根據第一個屬性判斷,如果是持有該鎖的那個線程又來lock,不會被阻塞(wait),而是在上鎖的次數加一(表示這個線程又鎖了一次(重入)),只有該線程unlock的次數達到上鎖的次數(即第二個屬性等於0),才會喚醒其他線程。

 

java中常用的可重入鎖:

synchronized

java.util.concurrent.locks.ReentrantLock

 

https://www.cnblogs.com/dj3839/p/6580765.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM