对可重入锁和不可重入锁的理解
可重入鎖:ReentrantLock
在學JUC的時候,聽到可重入鎖這個詞,不理解它的概念,網上搜索一番,還是有點迷糊,所以自己再來做一下筆記,理一理思路。
一、鎖是什么?
我們這里提到的鎖,是指把所需要的代碼塊,資源,或數據鎖上,在操作訪問他們的時候只允許一個線程去做操作。最終結果是為了保證cpu計算結果的正確性。
二、可重入鎖與不可重入鎖的區別?
1、不可重入鎖:
只判斷這個鎖有沒有被鎖上,只要被鎖上,申請鎖的線程都會被要求等待。實現簡單2、可重入鎖:
不僅判斷鎖有沒有被鎖上,還會判斷鎖是哪個線程鎖上的,當就是當前鎖上的時候,那么他依舊可以再次訪問臨界資源,并把加鎖次數加一。設計了加鎖次數,以實現在解鎖的時候,可以確保所有加鎖的過程都解鎖了,其他線程才能訪問。不然沒有加鎖的參考值,也就不知道什么時候解鎖?解鎖多少次?才能保證本線程已經訪問完臨界資源了可以喚醒其他線程訪問了。實現相對復雜。
3、結論:
這個重入的概念就是,拿到鎖的線程能不能多次以不同的方式訪問臨界資源而不出現死鎖等相關問題。經典之處就在于判斷了需要使用鎖的線程是否為加鎖的線程。如果是,則擁有重(chong)入的能力。
三、下面使用代碼來說明
1、不可重入鎖的理解:
public class Test{Lock lock = new Lock();public void methodA(){lock.lock();...........;methodB();...........;lock.unlock();}public void methodB(){lock.lock();...........;lock.unlock();} }當A方法獲取lock鎖去鎖住一段需要做原子性操作的B方法時,如果這段B方法又需要加鎖去做原子性操作,那么A方法就必定要與B方法出現死鎖。這種會出現問題的重入一把鎖的情況,叫不可重入鎖。
A方法需要等B方法執行完才能解鎖,但是B方法想執行完代碼又必須要lock鎖來加鎖。A的鎖未解鎖前,其他代碼塊無法使用此鎖來加鎖。這是由這個不可重入鎖決定的。
2、不可重入鎖的加鎖與解鎖(實現):
public class Lock{private boolean isLocked = false;public synchronized void lock() throws InterruptedException{while(isLocked){ wait();}isLocked = true;}public synchronized void unlock(){isLocked = false;notify();} }那么平時我們又有需要重入一把鎖的需求!!!!比如A方法是個原子性操作,但它有需要調用B方法的原子性操作,他們還爭搶的是同一個臨界資源,因此需要同一把鎖來加鎖
(ps:爭搶同一臨界資源的實質就是對同一把鎖的爭搶)
針對此情況,就有了可重入鎖的概念。
3、可重入鎖的實現:
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){isLocked = false;notify();}}} }現在我們來理解這段代碼,先看加鎖
3.1、lock()
isLocked:鎖的狀態。lockedBy:臨界資源被哪個線程鎖住了。Thread thread = Thread.currentThread(); 加鎖時,先獲取當前線程,識別誰需要鎖**while 判斷:當臨界資源已被鎖上,但當前請求鎖的線程又不是之前鎖上臨界資源的線程。那么當前請求鎖的線程需要等待。** while(isLocked && lockedBy != thread){wait(); }注意上面是個while,并且是個wait,因此當線程請求不到鎖的時候,就wait了。
不滿足while判斷條件的有3種情況:
在while條件不滿足時,那么當前線程可以加鎖:
isLocked = true; lockedCount++; lockedBy = thread;當前請求鎖的線程先把鎖加上,然后把上鎖次數+1,然后把自己(本線程)賦值給lockedBy,以說明當前誰用了這把鎖方便之后重入的時候做while判斷。
3.2、unlock()
再來看解鎖:
public synchronized void unlock(){if(Thread.currentThread() == this.lockedBy){lockedCount--;if(lockedCount == 0){isLocked = false;notify();}} }首先看看要求解鎖的線程是不是當前正在使用鎖的線程。不是則什么也不做。(這個判斷使為了保證當前要解鎖的線程必須也是加鎖的線程,誰加的誰來解。否則其他線程也能隨意的執行unlock代碼就能解鎖,那這樣相當于誰都有一把鑰匙了,加鎖也失去了意義)
如果解鎖的就是加鎖的線程。
那么把加鎖次數減一。
然后在判斷加鎖次數有沒有變為0。
變為 0 說明,這個鎖已經完全解鎖了。
鎖狀態標志 islocked 就可以復位為 false了。
并且隨機喚醒某個被 wait() 等待的線程 :notify()
這就是重入鎖的設計。
再次回顧上文所述的
4、可重入鎖和不可重入鎖的區別:
不可重入鎖:只判斷這個鎖有沒有被鎖上,只要被鎖上申請鎖的線程都會被要求等待。實現簡單
可重入鎖:不僅判斷鎖有沒有被鎖上,還會判斷鎖是誰鎖上的,當就是自己鎖上的時候,那么他依舊可以再次訪問臨界資源,并把加鎖次數加一。
設計了加鎖次數,以在解鎖的時候,可以確保所有加鎖的過程都解鎖了,其他線程才能訪問。不然沒有加鎖的參考值,也就不知道什么時候解鎖?解鎖多少次?才能保證本線程已經訪問完臨界資源了可以喚醒其他線程訪問了。實現相對復雜。
重入:指拿到鎖的線程能不能多次以不同的方式訪問臨界資源而不出現死鎖等相關問題。經典之處在于判斷了需要使用鎖的線程是否為加鎖的線程。如果是,則擁有重入的能力。
怎么樣,現在是不是理解更清晰了?
參考原文:https://blog.csdn.net/qq_29519041/article/details/86583945
總結
以上是生活随笔為你收集整理的对可重入锁和不可重入锁的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言程序设计教程本科,新编C语言程序设
- 下一篇: 一款轻量级的消息提示插件 —— toas