<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>

          獨家報道 lock.lock() 寫在 try 外面?

          共 1755字,需瀏覽 4分鐘

           ·

          2021-01-28 23:47

          前言

          面試官:小伙子,JUC 并發(fā)包下的可重入鎖 ReentrantLock 在代碼里實際使用過么

          混子:用過,ReentrantLock 是 JDK 提供的可重入的鎖。提供對 共享資源的獨占訪問,一次只能有一個線程可以獲取該鎖

          面試官:你覺得,ReentrantLock#lock 方法寫到 try 語句外面還是里面

          混子:我......

          面試官:我們不合適,你走吧

          先給出結(jié)論,lock.lock() 最規(guī)范的寫法是寫到 try 語句的外面

          lock.lock()

          默認小伙伴對 ReentrantLock 和 AQS 相關(guān)的知識是掌握的,不了解的朋友查看 《AQS 底層原理》

          Oracle 文檔中在介紹鎖的使用時有一段代碼,我們以 ReentrantLock 舉例,代碼如下所示:

          ReentrantLock?lock?=?new?ReentrantLock();
          lock.lock();
          try?{
          ????//?access?the?resource?protected?by?this?lock
          }?finally?{
          ????lock.unlock();
          }

          Q:為什么要把 lock.unlock() 放到 finally 語句塊?

          A:為了保證當(dāng)前線程執(zhí)行過程中出現(xiàn)異常時,鎖依然能被釋放掉,避免死鎖的產(chǎn)生

          我們來改動一下上面的代碼,看看會產(chǎn)生什么樣的影響

          ReentrantLock?lock?=?new?ReentrantLock();
          try?{
          ????lock.lock();
          ????//?access?the?resource?protected?by?this?lock
          }?finally?{
          ????lock.unlock();
          }

          看著沒問題呀,為啥文章開始不建議這么用?先說下可能會存在的問題

          異常堆棧丟失

          假設(shè)在 lock.lock 方法中加鎖異常(千萬不要杠),那么會進入 finally 語句塊中進行解鎖

          繼續(xù)跟進,看一下 lock.unlock() 源碼中是如何處理的

          d187996bf88f458c630fbda336c87266.webp

          lock.lock() 拋出異常有可能還沒獲取到鎖,那么 解鎖源碼中將當(dāng)前線程比較擁有鎖線程肯定是不相等的,所以會拋出 IMSE (IllegalMonitorStateException)異常

          我重寫了 ReentrantLock 加鎖代碼的邏輯,在里面拋出了異常,一起看下會出現(xiàn)什么情況

          final?void?lock()?{
          ????//?模擬加鎖未成功就拋出異常
          ????if?(true)?{
          ????????throw?new?RuntimeException("報錯啦!!!");
          ????}
          ????if?(compareAndSetState(0,?1))
          ????????setExclusiveOwnerThread(Thread.currentThread());
          ????else
          ????????acquire(1);
          }

          根據(jù)下圖可以看出 加鎖時異常堆棧被 "吞掉了",悄無聲息的就沒了。當(dāng)然這只是舉例,但是誰能保證加鎖未成功時不會拋出異常呢

          91c5ae86c18ca32060aaccab1be0d4f2.webp

          真實存在的 BUG

          上面代碼示例中都是在 try 的第一行寫 lock,出現(xiàn)問題的可能性極低。這里給大家提供一個反面教材,千萬千萬不要有這種類似行為

          a511c2fe9948fedc396da7592e695f32.webp

          示例代碼中把 lock 放到了 try 語句塊里,然后 lock 加鎖前面還有可能會產(chǎn)生異常的代碼,這種就涼了,誰用誰涼的那種

          結(jié)尾

          所以關(guān)于要不要把 lock.lock() 寫到 try 語句塊里,文章的結(jié)論是:

          1. 最好是把 lock.lock() 加鎖方法寫到 try 外面,這是一種規(guī)范,而不是強制
          2. 如果你非要寫到 try 里面,那么 請寫到 try 語句塊的第一行,或者 lock 加鎖方法前面不會存在可能出現(xiàn)異常的代碼
          3. 最后,如果你代碼中加鎖放到了 try 語句里,麻煩參考第 1 點



          - End -

          拉了一個 SpringCloud "純凈版"?群聊,群面主要分享以及討論 SpringCLoud 相關(guān)知識內(nèi)容,可以長按左下角圖片添加微信,備注【公眾號】拉你入群。

          9be837a4453920c9afa64eef38034712.webp

          關(guān)注公眾號后回復(fù) 123?領(lǐng)取內(nèi)容涵蓋 GO、Netty、Seata、SpringCloud Alibaba、開發(fā)規(guī)范、面試寶典、數(shù)據(jù)結(jié)構(gòu)等學(xué)習(xí)資料!

          瀏覽 138
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚洲中文字幕成人影视 | 日本婷婷网 | 影音先锋 亚洲无码 | 欧美性爱 国产精品 | 国产真实乱婬A片三区高 |