天天看點

可重入鎖與非可重入鎖

@[toc]

鎖的分類

可重入鎖與非可重入鎖

什麼是可重入鎖

可重入鎖又名遞歸鎖,是指在同一個線程在外層方法擷取鎖的時候,再進入該線程的内層方法會自動擷取鎖(前提鎖對象得是同一個對象或者class),不會因為之前已經擷取過還沒釋放而阻塞。Java中ReentrantLock和synchronized都是可重入鎖,可重入鎖的一個優點是可一定程度避免死鎖。
  • ReentrantLock和synchronized都是重入鎖,
  • 可重入鎖的好處:【1.避免死鎖】【2.提升封裝性】

案例實作

  • 電影院預定預定電影院座位

預定座位就是個很好的lock鎖場景,預定座位,其實這個背後就是上鎖了

可重入鎖與非可重入鎖
可重入鎖與非可重入鎖
可重入鎖與非可重入鎖

首先ReentrantLock和NonReentrantLock都繼承父類AQS,其父類AQS中維護了一個同步狀态status來計數重入次數,status初始值為0。

當線程嘗試擷取鎖時,可重入鎖先嘗試擷取并更新status值,如果status == 0表示沒有其他線程在執行同步代碼,則把status置為1,目前線程開始執行。如果status != 0,則判斷目前線程是否是擷取到這個鎖的線程,如果是的話執行status+1,且目前線程可以再次擷取鎖。而非可重入鎖是直接去擷取并嘗試更新目前status的值,如果status != 0的話會導緻其擷取鎖失敗,目前線程阻塞。

釋放鎖時,可重入鎖同樣先擷取目前status的值,在目前線程是持有鎖的線程的前提下。如果status-1 == 0,則表示目前線程所有重複擷取鎖的操作都已經執行完畢,然後該線程才會真正釋放鎖。而非可重入鎖則是在确定目前線程是持有鎖的線程之後,直接将status置為0,将鎖釋放。

測試lock 鎖的可重入性

可重入鎖與非可重入鎖

我們使用 lock.getHoldCount() 列印下擷取鎖的次數

多次擷取鎖,與釋放鎖

可重入鎖與非可重入鎖

會發現鎖不用等待,下一次依然可以擷取到鎖,這就是鎖的可重入鎖性

不可重入鎖

不可重入鎖,與可重入鎖相反,不可遞歸調用,遞歸調用就會發生死鎖。