可重入鎖 = 遞歸鎖。java
(官方概念)指的是同一線程外層函數得到鎖以後,內層遞歸函數仍然能獲取到該鎖的代碼,在同一線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。ide
指的是線程能夠進入任何一個它已經擁有的鎖所同步的代碼塊函數
public synchronized void method1() { method2(); } public synchronized void method2() { } /* method1和method2都是同步方法。咱們使 同步方法裏面再次訪問下一個同步方法。 */
比喻:只要家最外面的大門的鎖被打開了,那房間的鎖也能通行無阻測試
ReentrantLock
和 Synchronized
就是一個典型的可重入鎖spa
可重入鎖的最大做用就是避免死鎖線程
編寫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(); }
運行結果遞歸
sendSMS()
方法的時候,擁有了一把鎖,同時 B 線程沒法進入,直到 A 線程拿着鎖,執行了sendEmail()
方法後,才釋放鎖,這樣 B 纔可以進入。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(); }
ReentrantLock
進行驗證,首先資源類實現了Runnable接口,重寫Run方法,裏面調用getLock方法,getLock方法在進入的時候,就加了鎖。運行結果
最後輸出結果咱們能發現,結果和加synchronized方法是一致的,都是在外層的方法獲取鎖以後,線程可以直接進入裏層。
最後獲得的結果也是同樣的,由於裏面無論有幾把鎖,其它他們都是同一把鎖,也就是說用同一個鑰匙都可以打開
獲得結果
線程A得到鎖 線程A設置鎖
也就是說程序直接卡死,線程不能出來,也就說明咱們申請幾把鎖,最後就要解除幾把鎖。
運行程序會直接報錯!!