可重入鎖 VS 非可重入鎖

可重入鎖又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候,再進入該線程的內層方法會自動獲取鎖(前提鎖對象得是同一個對象或者class),不會因爲之前已經獲取過還沒釋放而阻塞。Java中ReentrantLock和synchronized都是可重入鎖,可重入鎖的一個優點是可一定程度避免死鎖。

之前我們說過ReentrantLock和synchronized都是重入鎖,那麼我們通過重入鎖ReentrantLock以及非可重入鎖NonReentrantLock的源碼來對比分析一下爲什麼非可重入鎖在重複調用同步資源時會出現死鎖。

首先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,將鎖釋放。

要點:

  • 可重入鎖的一個優點是可一定程度避免死鎖
  • AQS通過控制status狀態來判斷鎖的狀態,對於非可重入鎖狀態不是0則去阻塞;對於可重入鎖如果是0則執行,非0則判斷當前線程是否是獲取到這個鎖的線程,是的話把status狀態+1,釋放的時候,只有status爲0,纔將鎖釋放。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章