9.Java鎖之可重入鎖

概念

可重入鎖 = 遞歸鎖。java

(官方概念)指的是同一線程外層函數得到鎖以後,內層遞歸函數仍然能獲取到該鎖的代碼,在同一線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。ide

指的是線程能夠進入任何一個它已經擁有的鎖所同步的代碼塊函數

代碼解釋

public synchronized void method1() {
    method2();        
}
    
public synchronized void method2() {    
}
/*
    method1和method2都是同步方法。咱們使 同步方法裏面再次訪問下一個同步方法。
*/
  • 咱們若是得到了method1的鎖,method2也加鎖了,那麼它們擁有的是同一把鎖
  • 也就是說,咱們只要拿到method1方法的鎖,進入到method1後,能直接進入method2方法。由於他們的鎖是同一把。

比喻:只要家最外面的大門的鎖被打開了,那房間的鎖也能通行無阻測試

做用

ReentrantLockSynchronized 就是一個典型的可重入鎖spa

可重入鎖的最大做用就是避免死鎖線程

可重入鎖驗證

驗證Synchronized

編寫Phone類,在同步方法中,調用另一個同步方法。code

public class Phone {

    // 發送短信的方法
    public synchronized void sendSMS() {
    System.out.println(Thread.currentThread().getName() + "調用了sendSMS方法");
    sendEmail();    // 再同步方法內,調用另一個同步方法
    }

    // 發送郵件的方法
    public synchronized void sendEmail() {
        System.out.println(Thread.currentThread().getName() + "調用了sendEmail方法");
    }
}

測試blog

public static void main(String[] args) {
        Phone phone = new Phone();
        // A線程操做資源列
        new Thread(() -> {
            phone.sendSMS();
        }, "線程A").start();

        // B線程操做資源列
        new Thread(() -> {
            phone.sendSMS();
        }, "線程B").start();
    }

運行結果遞歸

  • 這就說明當 A 線程進入sendSMS()方法的時候,擁有了一把鎖,同時 B 線程沒法進入,直到 A 線程拿着鎖,執行了sendEmail()方法後,才釋放鎖,這樣 B 纔可以進入。

證實ReentrantLock

public class Phone implements Runnable {
    Lock lock = new ReentrantLock();
    
    //getLock方法
    public void getLock() {
        lock.lock();
        System.out.println(Thread.currentThread().getName() + "得到鎖");
        
        setLock();        //調用setLock方法
        
        lock.unlock();    
    }
    
    //setLock方法
    public void setLock() {
        lock.lock();
        System.out.println(Thread.currentThread().getName() + "設置鎖");
        lock.unlock();
    }

    //重寫run方法
    @Override
    public void run() {
        getLock();
    }
}

測試接口

public static void main(String[] args) {
        Phone phone = new Phone();

        // 由於Phone實現了Runnable接口
        Thread A = new Thread(phone, "線程A");
        Thread B = new Thread(phone, "線程B");
        A.start();
        B.start();
}
  1. 如今咱們使用ReentrantLock進行驗證,首先資源類實現了Runnable接口,重寫Run方法,裏面調用getLock方法,getLock方法在進入的時候,就加了鎖。
  2. 而後在方法裏面,又調用另一個加了鎖的setLock方法

運行結果

最後輸出結果咱們能發現,結果和加synchronized方法是一致的,都是在外層的方法獲取鎖以後,線程可以直接進入裏層。

  • 當咱們再getLock方法加兩把鎖會是什麼狀況呢?

最後獲得的結果也是同樣的,由於裏面無論有幾把鎖,其它他們都是同一把鎖,也就是說用同一個鑰匙都可以打開

  • 當咱們在getLock方法加兩把鎖,可是隻解一把鎖會出現什麼狀況呢?

獲得結果

線程A得到鎖
線程A設置鎖

也就是說程序直接卡死,線程不能出來,也就說明咱們申請幾把鎖,最後就要解除幾把鎖。

  • 當咱們只加一把鎖,可是用兩把鎖來解鎖的時候,又會出現什麼狀況呢?

運行程序會直接報錯!!

相關文章
相關標籤/搜索