<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:重入鎖的機(jī)制了解嗎?

          共 5621字,需瀏覽 12分鐘

           ·

          2021-10-01 08:18

          點(diǎn)擊“藍(lán)字”,關(guān)注,置頂公眾號(hào)

          每日技術(shù)干貨,第一時(shí)間送達(dá)!


          首先我們這里提到的鎖,是把所需要的代碼塊,資源,或數(shù)據(jù)鎖上,在操作他們的時(shí)候只允許一個(gè)線程去做操作。最終結(jié)果是為了保證cpu計(jì)算結(jié)果的正確性。


          對不可重入鎖的理解



          public class Test{
               Lock lock = new Lock();
               public void methodA(){
                   lock.lock();
                   ...........;
                   methodB();
                   ...........;
                   lock.unlock();
               }
               public void methodB(){
                   lock.lock();
                   ...........;
                   lock.unlock();
               }
          }



          當(dāng)A方法獲取lock鎖去鎖住一段需要做原子性操作的B方法時(shí),如果這段B方法又需要鎖去做原子性操作,那么A方法就必定要與B方法出現(xiàn)死鎖。這種會(huì)出現(xiàn)問題的重入一把鎖的情況,叫不可重入鎖。


          A方法需要等B方法執(zhí)行完才能解鎖,但是B方法想執(zhí)行完代碼又必須要lock鎖來加鎖。A的鎖未解鎖前,其他代碼塊無法使用此鎖來加鎖。這是由這個(gè)不可重入鎖決定的。


          不可重入鎖



          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();
              }
          }



          那么平時(shí)我們又有需要重入一把鎖的需求!!!!比如A方法是個(gè)原子性操作,但它有需要調(diào)用B方法的原子性操作,他們還爭搶的是同一個(gè)臨界資源,因此需要同一把鎖來加鎖(ps:爭搶同一臨界資源的實(shí)質(zhì)就是對同一把鎖的爭搶),歡迎關(guān)注我們,公號(hào)IT碼徒。


          針對此情況,就有了可重入鎖的概念:


          可重入鎖的實(shí)現(xiàn)



          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();
                      }
                  }
              }
          }



          可以看見代碼的核心概念是:


          首先解釋lockedBy:顧名思義,臨界資源被哪個(gè)線程鎖住了。


          加鎖時(shí),先獲取當(dāng)前線程。(識(shí)別誰需要鎖)



          Thread thread = Thread.currentThread();



          判斷:當(dāng)臨界資源已被鎖上,但當(dāng)前請求鎖的線程又不是之前鎖上臨界資源的線程。那么當(dāng)前請求鎖的線程需要等待。



          while(isLocked && lockedBy != thread){
                  wait();
          }



          注意上面是個(gè)while,并且是個(gè)wait,因此當(dāng)請求線程請求不到鎖的時(shí)候,就wait了。


          當(dāng)時(shí)當(dāng)while不滿足有的3種情況:


          A:當(dāng)前鎖沒有線程使用.


          B:當(dāng)前鎖有線程使用,當(dāng)前請求鎖的線程就是現(xiàn)在正在使用鎖的線程。


          C:當(dāng)前鎖沒有線程使用,當(dāng)前請求鎖的線程就是現(xiàn)在正在使用鎖的線程。(不可能出現(xiàn),鎖0沒有被用,哪還有線程使用鎖)


          來看看


          A:沒有線程使用:


          那么:



          isLocked = true;
          lockedCount++;
          lockedBy = thread;



          當(dāng)前請求鎖的線程先把鎖加上,然后把上鎖次數(shù)+1,然后把自己(本線程)賦值給lockedBy,以說明當(dāng)前誰用了這把鎖方便之后重入的時(shí)候做while判斷。


          再來看解鎖:



          public synchronized void unlock(){
              if(Thread.currentThread() == this.lockedBy){
                  lockedCount--;
                  if(lockedCount == 0){
                      isLocked = false;
                      notify();
                  }
              }
          }



          首先看看要求解鎖的線程是不是當(dāng)前用鎖的線程。不是則什么也不做。(當(dāng)然不能隨意讓其他的線程一執(zhí)行unlock代碼就能解鎖使用啊。那這樣相當(dāng)于誰都有一把鑰匙了,這里這個(gè)判斷也就是說明解鎖的必須是加鎖的)


          如果要求解鎖的就是加鎖的線程。


          那么把加鎖次數(shù)減一。


          然后在判斷加鎖次數(shù)有沒有變?yōu)?。


          變?yōu)?說明,這個(gè)鎖已經(jīng)完全解鎖了。鎖上標(biāo)識(shí)islocked可以復(fù)位了。


          并且隨機(jī)喚醒某個(gè)被wait()等待的線程 :notify()


          這就是重入鎖的設(shè)計(jì)。另外,關(guān)注Java技術(shù)精選公眾號(hào),回復(fù)“資料”,送你面試題寶典和大量視頻資源下載!


          它和不可重入鎖的設(shè)計(jì)不同之處:


          • 不可重入鎖:只判斷這個(gè)鎖有沒有被鎖上,只要被鎖上申請鎖的線程都會(huì)被要求等待。實(shí)現(xiàn)簡單

          • 可重入鎖:不僅判斷鎖有沒有被鎖上,還會(huì)判斷鎖是誰鎖上的,當(dāng)就是自己鎖上的時(shí)候,那么他依舊可以再次訪問臨界資源,并把加鎖次數(shù)加一。


          設(shè)計(jì)了加鎖次數(shù),以在解鎖的時(shí)候,可以確保所有加鎖的過程都解鎖了,其他線程才能訪問。不然沒有加鎖的參考值,也就不知道什么時(shí)候解鎖?解鎖多少次?才能保證本線程已經(jīng)訪問完臨界資源了可以喚醒其他線程訪問了。實(shí)現(xiàn)相對復(fù)雜。


          總結(jié)


          這個(gè)重入的概念就是,拿到鎖的代碼能不能多次以不同的方式訪問臨界資源而不出現(xiàn)死鎖等相關(guān)問題。經(jīng)典之處在于判斷了需要使用鎖的線程是否為加鎖的線程。如果是,則擁有重(chong)入的能力。



          往期推薦





          Mybatis 框架下 SQL 注入攻擊的 3 種方式,真是防不勝防!




          List 中 remove() 方法移除元素的【坑】

          厲害了,用 IDEA 神器看源碼,效率賊高!

          MyBatis vs Hibernate,到底哪個(gè)性能更好?

          如何設(shè)計(jì)一個(gè)小而美的搶紅包系統(tǒng)?

          來看看Redis 分布式鎖的正確實(shí)現(xiàn)方式

          IntelliJ idea 高效使用教程,一勞永逸!


          瀏覽 26
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产丝袜网站 | 狠狠躁日日躁夜夜躁 | 欧美操逼大全 | 中文字幕在线播放第二页 | 国产一卡二卡三卡在线观看 |