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

          從零到一實(shí)現(xiàn)互斥鎖,理清AQS和Lock的關(guān)系。

          共 3512字,需瀏覽 8分鐘

           ·

          2020-08-11 01:28

          作者:Mulavar

          來(lái)源:SegmentFault社區(qū)




          1. AQS原理


          1.1 AQS簡(jiǎn)介


          AQS全名AbstractQueuedSynchronizer,是一個(gè)隊(duì)列同步器,JUC的鎖和同步組件都是基于AQS構(gòu)建的。AQS的結(jié)構(gòu)主要分兩部分:


          • state:用了violate關(guān)鍵字修飾的int類型成員變量,表示同步狀態(tài),每次更新都能被所有線程可見(jiàn);
          • head、tail:內(nèi)置的Node類型(Node包含當(dāng)前線程、等待狀態(tài)等信息),組成了一個(gè)FIFO的同步隊(duì)列。


          AQS的主要使用方式是繼承,它采用了模板方法的設(shè)計(jì)模式。什么是模板方法設(shè)計(jì)模式?簡(jiǎn)單來(lái)說(shuō),就是一個(gè)類將一些不變行為封裝成final方法(即模板方法),將剩余的可變方法(abstract)留給子類實(shí)現(xiàn)去拓展。


          1.2 AQS接口


          AQS主要提供了如下三個(gè)方法來(lái)訪問(wèn)或修改同步狀態(tài)state:


          • getState():獲取當(dāng)前同步狀態(tài)
          • setState(int newState):設(shè)置當(dāng)前同步狀態(tài)
          • compareAndSetState(int expect, int update):使用CAS設(shè)置當(dāng)前狀態(tài),該方法能夠保證狀態(tài)設(shè)置的原子性。


          1.2.1 AQS模板方法



          下面列舉幾個(gè)最為核心的模板方法:


          1.2.2 AQS重寫接口


          而AQS可重寫的方法如下:


          可以看到,AQS利用模板方法主要做了兩件事:


          1. 嘗試獲取或設(shè)置同步狀態(tài)
          2. 維護(hù)同步隊(duì)列


          而留給開(kāi)發(fā)者的可重寫方法更多聚焦于如何設(shè)置、獲取同步狀態(tài),這種設(shè)計(jì)思想與雙親委派機(jī)制有點(diǎn)相似:loadClass中實(shí)現(xiàn)了雙親委派機(jī)制,而用戶可以通過(guò)重寫findClass去實(shí)現(xiàn)自己加載類的具體邏輯。





          2. Lock和AQS的關(guān)系


          AQS是實(shí)現(xiàn)Lock的基礎(chǔ),兩者之間的主要區(qū)別在于:


          • Lock面向鎖的使用者,它聚焦的問(wèn)題是使用者如何更好地使用鎖處理并發(fā)問(wèn)題,而使用者不需要知道鎖的實(shí)現(xiàn)細(xì)節(jié)就可以實(shí)現(xiàn)互斥同步;
          • AQS面向鎖的開(kāi)發(fā)者,它關(guān)注的兩個(gè)主要問(wèn)題是同步狀態(tài)管理以及維護(hù)線程的同步等待隊(duì)列。




          3. 自定義實(shí)現(xiàn)獨(dú)占鎖


          該節(jié)通過(guò)自定義實(shí)現(xiàn)獨(dú)占鎖Demo,去更加清晰揭示AQS和Lock接口的區(qū)別。


          首先,我們定義了一個(gè)獨(dú)占鎖—Mutex實(shí)現(xiàn)Lock接口,并實(shí)現(xiàn)該接口的所有方法。而Lock接口的方法實(shí)現(xiàn)中所做的是都是調(diào)用AQS的模板方法。


          其次,我們創(chuàng)建了一個(gè)內(nèi)部類—Sync,實(shí)現(xiàn)了一個(gè)自定義同步器,并重寫了其中的所有非模板方法,主要思想是通過(guò)getState()、setState(int newState)和compareAndSetState(int expect, int update)三個(gè)方法去設(shè)置和獲取同步狀態(tài),具體實(shí)現(xiàn)可看代碼注釋。


          至此我們總結(jié)一下其中的一個(gè)核心調(diào)用鏈lock --> acquire() --> tryAcquire():


          • lock:面向用戶提供鎖功能
          • acquire:嘗試設(shè)置同步狀態(tài)并維護(hù)同步隊(duì)列
          • tryAquire:設(shè)置同步狀態(tài)的真正邏輯
          import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.AbstractQueuedSynchronizer;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;  /** * @author Lam * @date 2020/7/27 */public class Mutex implements Lock {    private final Sync sync = new Sync();          /**     * 同步器實(shí)現(xiàn),重寫非模板方法     * 主要思想是使用CAS設(shè)置state的狀態(tài)     */    private static class Sync extends AbstractQueuedSynchronizer {
          @Override protected boolean tryAcquire(int arg) { // CAS設(shè)置state if (compareAndSetState(0, 1)) { // 設(shè)置該線程為成功獲取同步狀態(tài)的線程 setExclusiveOwnerThread(Thread.currentThread()); return true; }
          // 設(shè)置狀態(tài)失敗 return false; } @Override protected boolean tryRelease(int arg) { // 若此時(shí)同步狀態(tài)為0說(shuō)明沒(méi)有線程設(shè)置過(guò)同步狀態(tài) if (getState()==0) { throw new IllegalMonitorStateException(); }
          // 清空成功獲取同步狀態(tài)的線程信息 setExclusiveOwnerThread(null);
          // 清除狀態(tài) setState(0); return true; } @Override protected boolean isHeldExclusively() { return getState() == 1; } /** * 該方法不是AQS的重寫方法,只是為了代碼風(fēng)格統(tǒng)一將邏輯都放到Sync中 */ Condition newCondition() { // 返回一個(gè)等待通知組件 return new ConditionObject(); } } /** * Lock接口的實(shí)現(xiàn) */ @Override public void lock() { sync.acquire(1); } @Override public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } @Override public boolean tryLock() { return sync.tryAcquire(1); } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(time)); } @Override public void unlock() { sync.release(1); } @Override public Condition newCondition() { return sync.newCondition(); }}




          4. 總結(jié)


          本文大部分內(nèi)容取自Java并發(fā)編程的藝術(shù),在一些小地方做了刪改并加了自己的理解,如果想更完全深入了解AQS的模板方法和非模板方法有哪些可以查看原書第五章的1、2節(jié)。





          -?END -

          瀏覽 57
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  欧美成人视频在线观看 | 国产精品久久久久久久久久久久久久久 | 19日韩福利视频 | 国产黄色一级大片 | 日本高清中文不卡 |