java并發(fā)編程(十七)帶你了解什么是面試官常說的AQS

前面我們學習了ReentrantLock苇侵,其底層就是用了AQS實現(xiàn)的庆聘,應該先講這一章節(jié),但是當時給忘了,現(xiàn)在給補上吧奴艾。

關于ReentrantLock的學習肌厨,可以參考:http://www.reibang.com/p/edec5185196d

AbstractQueuedSynchronizer是阻塞式鎖脸哀,以及同步器組件的實現(xiàn)框架每篷。是JDK中實現(xiàn)并發(fā)編程的核心,它提供了一個基于FIFO隊列镐牺,平時我們工作中經(jīng)常用到的ReentrantLock炫掐,CountDownLatch等都是基于它來實現(xiàn)的。

一睬涧、初識AQS

首先我們還是從前面學習的ReentrantLock入手募胃,看看其代碼結構是什么樣的:

ReentrantLockl類圖

從上圖可以看到以下幾點:

  • ReentrantLock實現(xiàn)接口Lock(抽象接口)
  • ReentrantLock有三個內(nèi)部類,分別是FrairSync畦浓、NonfairSync痹束、Sync,且FrairSync讶请、NonfairSync繼承自Sync祷嘶。
  • Sync繼承AbstractQueuedSynchronizer
  • AbstractQueuedSynchronizer有兩個內(nèi)部類,分別是Node、ConditionObject论巍。
  • AbstractQueuedSynchronizer繼承自AbstractOwnableSynchronizer(抽象類烛谊,提供獨占線程的get和set)。

AQS有如下的特點:

  • 用 state 屬性來表示資源的狀態(tài)嘉汰,包含獨占狀態(tài)和共享狀態(tài)丹禀,對應公平鎖和非公平鎖。子類需要定義如何維護這個狀態(tài)鞋怀,控制如何獲取鎖和釋放鎖双泪,如上面圖中的關系,公平鎖和非公平鎖需要各自去維護這個state密似,達到獲取和釋放鎖的目的攒读。

    • getState - 獲取 state 狀態(tài)
    • setState - 設置 state 狀態(tài)
    • compareAndSetState - 使用CAS設置狀態(tài)
    • 獨占模式:只有一個線程能夠訪問資源
    • 共享模式:允許多個線程訪問資源
  • 提供了基于 FIFO 的等待隊列,類似于前面講Synchronized原理提到的 Monitor 的 EntryList

  • 使用條件變量來實現(xiàn)等待隊列辛友、線程喚醒機制,同時支持多個條件變量剪返,類似于前面講Synchronized原理提到的 Monitor 的 WaitSet

  • 【公平鎖】與【非公平鎖】:二者的區(qū)別主要在于獲取鎖是否和排隊順序有關废累。當鎖唄一個線程持有,其他嘗試獲取鎖的線程會被掛起脱盲,加到等待隊列中邑滨,先被掛起的在隊列的最前端。當鎖被釋放钱反,需要通知隊列中的線程掖看。作為公平鎖,會先喚醒隊列最前端的線程面哥;而非公平鎖會喚醒所有線程哎壳,通過競爭去獲取鎖,后來的線程有可能獲得鎖尚卫。

二归榕、 源碼分析

下面我們通過源碼剖析其本質(zhì)是什么樣的。

首先在腦海中有個印象吱涉,AQS維護了兩個對個隊列刹泄,一個是同步隊列,一個是阻塞隊列怎爵。

Node可以說是【同步隊列】和【阻塞隊列】的節(jié)點特石。

2.1 Node源碼剖析

  static final class Node {
    // 模式,分為共享與獨占
    // 共享模式
    static final Node SHARED = new Node();
    // 獨占模式
    static final Node EXCLUSIVE = null;        
    // 結點狀態(tài)
    // CANCELLED鳖链,值為1姆蘸,表示當前的線程被取消
    // SIGNAL,值為-1,表示當前節(jié)點的后繼節(jié)點包含的線程需要運行乞旦,也就是unpark
    // CONDITION贼穆,值為-2,表示當前節(jié)點在等待condition兰粉,也就是在condition隊列中
    // PROPAGATE故痊,值為-3,表示當前場景下后續(xù)的acquireShared能夠得以執(zhí)行
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;        

    // 結點狀態(tài)
    volatile int waitStatus;        
    // 前驅(qū)結點
    volatile Node prev;    
    // 后繼結點
    volatile Node next;        
    // 結點所對應的線程
    volatile Thread thread;        
    // 下一個等待者
    Node nextWaiter;
    
    // 結點是否在共享模式下等待
    final boolean isShared() {
        return nextWaiter == SHARED;
    }
    
    // 獲取前驅(qū)結點玖姑,若前驅(qū)結點為空愕秫,拋出異常
    final Node predecessor() throws NullPointerException {
        // 保存前驅(qū)結點
        Node p = prev; 
        if (p == null) // 前驅(qū)結點為空,拋出異常
            throw new NullPointerException();
        else // 前驅(qū)結點不為空焰络,返回
            return p;
    }
    
    // 無參構造函數(shù)
    Node() {    // Used to establish initial head or SHARED marker
    }
    
    // 構造函數(shù)戴甩,被addWaiter使用
     Node(Thread thread, Node mode) {    // Used by addWaiter
        this.nextWaiter = mode;
        this.thread = thread;
    }
    
    // 構造函數(shù)
    Node(Thread thread, int waitStatus) { // Used by Condition
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

2.2 ConditionObject源碼剖析

實現(xiàn)了condition接口,關于condition的學習后面會介紹闪彼,在學習ReentrantLock時也介紹了其使用方式甜孤。

代碼較多,直接從上向下看吧:

 // 內(nèi)部類
public class ConditionObject implements Condition, java.io.Serializable {
    // 版本號
    private static final long serialVersionUID = 1173984872572414699L;
    
    // condition隊列的頭結點
    private transient Node firstWaiter;
    
    // condition隊列的尾結點
    private transient Node lastWaiter;

    /**
     *  構造函數(shù)
     */
    public ConditionObject() { }

    /**
     * 添加新的waiter到wait隊列
     */
    private Node addConditionWaiter() {
        // 定義尾結點是t
        Node t = lastWaiter;
       // 尾結點不為空畏腕,并且尾結點的狀態(tài)不為CONDITION(默認是-2缴川,表示當前節(jié)點在conditionObject等待隊列中)
        if (t != null && t.waitStatus != Node.CONDITION) { 
            // 清除狀態(tài)不為CONDITION的結點,對firstWaiter和lastWaiter重新賦值
            unlinkCancelledWaiters(); 
            // 將最后一個結點重新賦值給t
            t = lastWaiter;
        }
        // 新建一個結點
        Node node = new Node(Thread.currentThread(), Node.CONDITION);
        // 尾結點為空
        if (t == null) 
            // 設置condition隊列的頭結點
            firstWaiter = node;
        else 
            // 設置為節(jié)點的nextWaiter域為node結點
            t.nextWaiter = node;
        // 更新condition隊列的尾結點
        lastWaiter = node;
        return node;
    }

    /**
     *  移除或轉(zhuǎn)移頭結點到sync隊列描馅,直到?jīng)]有取消的或者空為止
     */
    private void doSignal(Node first) {
        // 循環(huán)
        do {
            // 將下一個節(jié)點設為首節(jié)點把夸,如果為空
            if ( (firstWaiter = first.nextWaiter) == null) 
                // 設置尾結點為空
                lastWaiter = null;
            // 設置first結點的nextWaiter域
            first.nextWaiter = null;
        } while (!transferForSignal(first) &&
                 (first = firstWaiter) != null); // 將結點從condition隊列轉(zhuǎn)移到sync隊列失敗并且condition隊列中的頭結點不為空,一直循環(huán)
    }

    /**
     * 轉(zhuǎn)移所有等待隊列的節(jié)點到同步隊列
     */
    private void doSignalAll(Node first) {
        // condition隊列的頭結點尾結點都設置為空
        lastWaiter = firstWaiter = null;
        // 循環(huán)
        do {
            // 獲取first結點的nextWaiter域結點
            Node next = first.nextWaiter;
            // 設置first結點的nextWaiter域為空
            first.nextWaiter = null;
            // 將first結點從condition隊列轉(zhuǎn)移到sync隊列
            transferForSignal(first);
            // 重新設置first
            first = next;
        } while (first != null);
    }

    /**
     * 過濾掉狀態(tài)不為CONDITION的節(jié)點
     * 對firstWaiter和lastWaiter重新賦值
     **/
    private void unlinkCancelledWaiters() {
        // 獲取condition隊列頭結點
        Node t = firstWaiter;
        // 獲取一個尾結點是null
        Node trail = null;
        while (t != null) {
            // 獲取下一個結點
            Node next = t.nextWaiter;
            // 頭結點的狀態(tài)不為CONDTION狀態(tài)
            if (t.waitStatus != Node.CONDITION) { 
                // 設置t節(jié)點的下一個等待者為空
                t.nextWaiter = null;
                if (trail == null) // trail為空铭污,首次進來一定為空
                    // 重新設置condition隊列的頭結點
                    firstWaiter = next;
                else 
                    // 設置trail結點的nextWaiter域為next結點
                    trail.nextWaiter = next;
                if (next == null) // next結點為空
                    // 設置condition隊列的尾結點
                    lastWaiter = trail;
            }
            else // t結點的狀態(tài)為CONDTION狀態(tài)
                // 設置trail結點
                trail = t;
            // 設置t結點
            t = next;
        }
    }

    /**
     * 實現(xiàn)Condition接口的signal方法
     */
    public final void signal() {
        if (!isHeldExclusively()) // 不被當前線程獨占恋日,拋出異常
            throw new IllegalMonitorStateException();
        // 保存condition隊列頭結點
        Node first = firstWaiter;
        if (first != null) // 頭結點不為空
            // 喚醒一個等待線程,將頭結點從阻塞隊列移除嘹狞,添加到同步隊列
            doSignal(first);
    }

    /**
     * 實現(xiàn)Condition的signalAll方法岂膳,喚醒所有線程
     */
    public final void signalAll() {
        if (!isHeldExclusively()) // 不被當前線程獨占,拋出異常
            throw new IllegalMonitorStateException();
        // 保存condition隊列頭結點
        Node first = firstWaiter;
        if (first != null) // 頭結點不為空
            // 喚醒所有等待線程磅网,將頭結點從阻塞隊列移除闷营,添加到同步隊列
            doSignalAll(first);
    }

    /**
     * 與await()區(qū)別在于,使用await方法知市,調(diào)用interrupt()中斷后會報錯傻盟,而該方法不會報錯。
     */
    public final void awaitUninterruptibly() {
        // 添加一個結點到等待隊列
        Node node = addConditionWaiter();
        // 獲取釋放的狀態(tài)
        int savedState = fullyRelease(node);
        boolean interrupted = false;
        while (!isOnSyncQueue(node)) { // 
            // 阻塞當前線程
            LockSupport.park(this);
            if (Thread.interrupted()) // 當前線程被中斷
                // 設置interrupted狀態(tài)
                interrupted = true; 
        }
        if (acquireQueued(node, savedState) || interrupted) // 
            selfInterrupt();
    }

    /**
     *  等待嫂丙,當前線程在接到信號或被中斷之前一直處于等待狀態(tài)
     */
    public final void await() throws InterruptedException {
        // 當前線程被中斷娘赴,拋出異常
        if (Thread.interrupted()) 
            throw new InterruptedException();
        // 將當前線程包裝成Node跟啤,尾插入到等待隊列中
        Node node = addConditionWaiter();
        // 釋放當前線程所占用的lock诽表,在釋放的過程中會喚醒同步隊列中的下一個節(jié)點
        int savedState = fullyRelease(node);
        int interruptMode = 0;
        while (!isOnSyncQueue(node)) {
            // 當前線程進入到等待狀態(tài)
            LockSupport.park(this);
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) // 檢查結點等待時的中斷類型
                break;
        }
        // 自旋等待獲取到同步狀態(tài)(即獲取到lock)
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (node.nextWaiter != null) // clean up if cancelled
            unlinkCancelledWaiters();
        // 處理被中斷的情況
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
    }

    /**
     * 等待唉锌,當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態(tài)
     */
    public final long awaitNanos(long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        Node node = addConditionWaiter();
        int savedState = fullyRelease(node);
        final long deadline = System.nanoTime() + nanosTimeout;
        int interruptMode = 0;
        while (!isOnSyncQueue(node)) {
            if (nanosTimeout <= 0L) {
                transferAfterCancelledWait(node);
                break;
            }
            if (nanosTimeout >= spinForTimeoutThreshold)
                LockSupport.parkNanos(this, nanosTimeout);
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                break;
            nanosTimeout = deadline - System.nanoTime();
        }
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (node.nextWaiter != null)
            unlinkCancelledWaiters();
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
        return deadline - System.nanoTime();
    }

    /**
     * 等待竿奏,當前線程在接到信號袄简、被中斷或到達指定最后期限之前一直處于等待狀態(tài)
     */
    public final boolean awaitUntil(Date deadline)
            throws InterruptedException {
        long abstime = deadline.getTime();
        if (Thread.interrupted())
            throw new InterruptedException();
        Node node = addConditionWaiter();
        int savedState = fullyRelease(node);
        boolean timedout = false;
        int interruptMode = 0;
        while (!isOnSyncQueue(node)) {
            if (System.currentTimeMillis() > abstime) {
                timedout = transferAfterCancelledWait(node);
                break;
            }
            LockSupport.parkUntil(this, abstime);
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                break;
        }
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (node.nextWaiter != null)
            unlinkCancelledWaiters();
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
        return !timedout;
    }

    /**
     * 等待,當前線程在接到信號泛啸、被中斷或到達指定等待時間之前一直處于等待狀態(tài)绿语。此方法在行為上等              
     * 效于:awaitNanos(unit.toNanos(time)) > 0
     */
    public final boolean await(long time, TimeUnit unit)
            throws InterruptedException {
        long nanosTimeout = unit.toNanos(time);
        if (Thread.interrupted())
            throw new InterruptedException();
        // 1. 將當前線程包裝成Node,尾插入到等待隊列中
        Node node = addConditionWaiter();
        // 2. 釋放當前線程所占用的lock候址,在釋放的過程中會喚醒同步隊列中的下一個節(jié)點
        int savedState = fullyRelease(node);
        final long deadline = System.nanoTime() + nanosTimeout;
        boolean timedout = false;
        int interruptMode = 0;
        while (!isOnSyncQueue(node)) {
            if (nanosTimeout <= 0L) {
                timedout = transferAfterCancelledWait(node);
                break;
            }
            if (nanosTimeout >= spinForTimeoutThreshold)
                LockSupport.parkNanos(this, nanosTimeout);
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                break;
            nanosTimeout = deadline - System.nanoTime();
        }
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (node.nextWaiter != null)
            unlinkCancelledWaiters();
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
        return !timedout;
    }

2.3 鎖的獲取和釋放

整個AQS的設計理念就是通過state字段來實現(xiàn)鎖的獲取和釋放吕粹,鎖有主要分為公平鎖和非公平鎖。

2.3.1 公平鎖

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            // 繼承自AQS的方法岗仑,內(nèi)部先調(diào)用tryAcquire獲取鎖匹耕,獲取失敗則添加下城到等待隊列當中
            acquire(1);
        }

        /**
         * 公平鎖版本的tryAcquire
         */
        protected final boolean tryAcquire(int acquires) {
            // 獲取當前線程
            final Thread current = Thread.currentThread();
            // 獲取鎖的狀態(tài)
            int c = getState();
            // 0表示鎖沒有被持有
            if (c == 0) {
                // 判斷當前等待隊列是否有節(jié)點在等待,沒有才去競爭
                if (!hasQueuedPredecessors() &&
                    // 比較并替換狀態(tài)
                    compareAndSetState(0, acquires)) {
                    // 設置當前線程為獨占線程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                // 此處表示鎖重入
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

2.3.2 非公平鎖

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * 立即獲取鎖荠雕,失敗會加入等待隊列
         */
        final void lock() {
            // 通過CAS嘗試獲取鎖稳其,成功則設置當前線程獨占
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                // 否則加入等待隊列·····································································································································
                acquire(1);
        }

        /** 
          * 非公平鎖版本的tryAcquire
          */
        protected final boolean tryAcquire(int acquires) {
            // 走其父類Sync的默認nonfairTryAcquire
            return nonfairTryAcquire(acquires);
        }
    }

2.3.3 Syc子類

這是公平鎖和非公平鎖的父類,提供統(tǒng)一的tryRelease方法釋放鎖

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * 提供非公平版本的快捷路徑
         */
        abstract void lock();

        /**
         * 非公平鎖獲取炸卑,默認就是非公平鎖
         */
        final boolean nonfairTryAcquire(int acquires) {
            // 獲取當前線程
            final Thread current = Thread.currentThread();
            // 獲取當前鎖的狀態(tài)
            int c = getState();
            // 0表示沒有被占用
            if (c == 0) {
                // CAS占用既鞠,成功則設置當前線程為獨占鎖
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 當前線程是獨占鎖,表示鎖重入
            else if (current == getExclusiveOwnerThread()) {
                // 狀態(tài) + 1
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                // 設置當前狀態(tài)
                setState(nextc);
                return true;
            }
            return false;
        }

         /**
         * 釋放鎖
         */
        protected final boolean tryRelease(int releases) {
            // 當前狀態(tài) 減去 釋放的數(shù)量
            int c = getState() - releases;
            // 如果當前線程不是占有鎖的線程矾兜,拋出異常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            // 當全部釋放后,狀態(tài)為0患久,取消獨占線程
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            // 設置狀態(tài)為0椅寺,返回釋放成功
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // 當前線程是否是鎖持有者
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        // 獲取當前持有者
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        // 獲取持有數(shù),只有是線程持有者才能獲取
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
    }

3.3.4 acquire 和 release

在AQS當中還有兩個核心方法:

  • acquire():獲取鎖蒋失,這是實際鎖調(diào)用上鎖的真正方法返帕,前面的try開頭的知識嘗試獲取鎖,即使失敗也不會添加到等待隊列篙挽。
    public final void acquire(int arg) {
      // 嘗試獲取
      if (!tryAcquire(arg) &&
          // 嘗試獲取成功荆萤,以獨占方式添加到等待隊列,并不斷地嘗試占有鎖知道成功
          acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
          selfInterrupt();
  }
  • release():釋放鎖铣卡,這是實際釋放鎖的方法链韭,會調(diào)用鎖自定義的同步器實現(xiàn)的tryRelease方法:
        /**
          * 嘗試釋放,成功后返回true
          */
        public final boolean release(int arg) {
          if (tryRelease(arg)) {
              Node h = head;
              if (h != null && h.waitStatus != 0)
                  unparkSuccessor(h);
              return true;
          }
          return false;
      }
    

后面我們自定義不可重入鎖煮落,來看看同步器和鎖的關系是什么樣的敞峭,加深理解。

2.4 簡單總結

到此為止蝉仇,通過閱讀前面的源碼內(nèi)容旋讹,我們可以有如下的總結:

  • 鎖的釋放和獲取都是圍繞 【state】來做的殖蚕,0表示未持有鎖,1表示獨占沉迹,大于一表示鎖重入
  • 獲取鎖的姿勢如下:
      // 如果獲取鎖失敗
      if (!tryAcquire(arg)) {
        // 入隊, 可以選擇阻塞當前線程 park unpark
      }
    
  • 釋放鎖的姿勢如下:
      // 如果獲取鎖成功
      if (!tryRelease(arg)) {
        // 讓阻塞線程恢復運行
      }
    

三睦疫、實踐

了解了AQS的結構之后,我們不妨自己動手實踐一番鞭呕。加深理解蛤育。

定義一個不可重入鎖,需要一個同步器琅拌,一個鎖缨伊,一個測試類

自定義同步器:

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * @description: 實現(xiàn)一個不可重入鎖 同步器,state最大只能是1
 * @author:weirx
 * @date:2022/1/13 13:49
 * @version:3.0
 */
public class MyLockSynchronizer extends AbstractQueuedSynchronizer {

    @Override
    protected boolean tryAcquire(int acquires) {
        int state = getState();
        if (state == 0) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
        }
        return false;
    }

    @Override
    protected boolean tryRelease(int acquires) {
        int c = getState() - acquires;
        if (c == 0) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        return false;
    }

    @Override
    protected boolean isHeldExclusively() {
        return getState() == 1;
    }

    protected ConditionObject newCondition() {
        return new ConditionObject();
    }
}

自定義鎖:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @description: 自定義鎖
 * @author:weirx
 * @date:2022/1/13 14:05
 * @version:3.0
 */
public class MyLock implements Lock {

    MyLockSynchronizer myLockSynchronizer = new MyLockSynchronizer();

    @Override
    public void lock() {
        // 嘗試獲取鎖进宝,失敗則加入等待隊列
        myLockSynchronizer.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        // 嘗試獲取鎖刻坊,失敗則加入等待隊列, 可中斷
        myLockSynchronizer.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        // 嘗試獲取鎖,不加入等待隊列
        return myLockSynchronizer.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        // 嘗試獲取鎖党晋,不加入等待隊列,有實現(xiàn)
        return myLockSynchronizer.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        // 釋放鎖
        myLockSynchronizer.release(1);
    }

    @Override
    public Condition newCondition() {
        // 條件變量
        return myLockSynchronizer.newCondition();
    }
}

測試鎖的效果:

/**
 * @description: 測試
 * @author:weirx
 * @date:2022/1/13 14:24
 * @version:3.0
 */
public class TestMyLock {

    public static void main(String[] args) {
        MyLock myLock = new MyLock();

        new Thread(() -> {
            try {
                myLock.lock();
                System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                        + " " + Thread.currentThread().getName() + " :acquire lock success");

                // 休眠一秒看效果
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                myLock.unlock();
                System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                        + " " + Thread.currentThread().getName() + " :release lock success");
            }

        }, "t1").start();

        new Thread(() -> {
            try {
                myLock.lock();
                System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                        + " " + Thread.currentThread().getName() + " :acquire lock success");
            } finally {
                myLock.unlock();
                System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
                        + " " + Thread.currentThread().getName() + " :release lock success");
            }
        }, "t2").start();
    }
}

結果谭胚,ti一秒后釋放鎖,才會由t2獲得鎖:

2022-01-13 14:34:56 t1 :acquire lock success
2022-01-13 14:34:57 t2 :acquire lock success
2022-01-13 14:34:57 t1 :release lock success
2022-01-13 14:34:57 t2 :release lock success

測試下不可重入是否好使未玻,只需要在上述測試代碼的線程t1中灾而,再次使用myLock.lock()獲取一次鎖,發(fā)現(xiàn)扳剿,整個程序被卡住了旁趟,只會打印一條信息:

2022-01-13 14:35:56 t1 :acquire lock success

四、關于Condition的補充

本篇沒有介紹Condition的具體內(nèi)容庇绽,但是在之前講解ReentrantLock提到過【條件變量】锡搜,可以返回去看這篇文章了解其用法:http://www.reibang.com/p/edec5185196d


源碼學習真是難,看別人說的再多不如自己跟著走一遍瞧掺,建議同學們參照本文自己跟蹤一遍耕餐。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市辟狈,隨后出現(xiàn)的幾起案子肠缔,更是在濱河造成了極大的恐慌,老刑警劉巖哼转,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件明未,死亡現(xiàn)場離奇詭異,居然都是意外死亡壹蔓,警方通過查閱死者的電腦和手機亚隅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庶溶,“玉大人煮纵,你說我怎么就攤上這事懂鸵。” “怎么了行疏?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵匆光,是天一觀的道長。 經(jīng)常有香客問我酿联,道長终息,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任贞让,我火速辦了婚禮周崭,結果婚禮上,老公的妹妹穿的比我還像新娘喳张。我一直安慰自己续镇,他們只是感情好,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布销部。 她就那樣靜靜地躺著摸航,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舅桩。 梳的紋絲不亂的頭發(fā)上酱虎,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天,我揣著相機與錄音擂涛,去河邊找鬼读串。 笑死,一個胖子當著我的面吹牛撒妈,可吹牛的內(nèi)容都是我干的恢暖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼踩身,長吁一口氣:“原來是場噩夢啊……” “哼胀茵!你這毒婦竟也來了社露?” 一聲冷哼從身側(cè)響起挟阻,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎峭弟,沒想到半個月后附鸽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡瞒瘸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年坷备,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片情臭。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡省撑,死狀恐怖赌蔑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情竟秫,我是刑警寧澤娃惯,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站肥败,受9級特大地震影響趾浅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜馒稍,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一皿哨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纽谒,春花似錦证膨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至请祖,卻和暖如春订歪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肆捕。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工刷晋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人慎陵。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓眼虱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親席纽。 傳聞我的和親對象是個殘疾皇子捏悬,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容