首頁 > 軟體

Java利用AQS實現自定義鎖

2022-07-25 18:06:17

什麼是AQS

AQS(AbstractQueuedSynchronizer),中文名抽象佇列同步器

AQS定義了一套多執行緒存取共用資源的同步器框架,主要用來自定義鎖和同步器

AQS原理

AQS 核心思想:

  • 如果被請求的共用資源空閒,則將當前請求資源的執行緒設定為有效的工作執行緒,並且將共用資源設定為鎖定狀態。
  • 如果被請求的共用資源被佔用,將暫時獲取不到鎖的執行緒加入到阻塞佇列中,等待被喚醒和鎖的分配

實現核心思想的的佇列:CLH佇列

CLH佇列是一個虛擬的雙向佇列,AQS 是將每條請求共用資源的執行緒封裝成一個 CLH 鎖佇列的一個結點(Node)來實現鎖的分配。

共用資源用 volatile 關鍵詞修飾,保證執行緒間的可見性

   /**
     * The synchronization state.
     */
    private volatile int state;

0狀態表示空閒,1狀態或以上表示不空閒

共用資源(state)的存取方式有三種:  

  1. getState()   獲得共用資源狀態
  2. setState()   設定共用資源狀態
  3. compareAndSetState() 更改共用資源狀態(底層unsafe類)

 原始碼如下

    /**
     * Returns the current value of synchronization state.
     * This operation has memory semantics of a {@code volatile} read.
     * @return current state value
     */
    protected final int getState() {
        return state;
    }
 
    /**
     * Sets the value of synchronization state.
     * This operation has memory semantics of a {@code volatile} write.
     * @param newState the new state value
     */
    protected final void setState(int newState) {
        state = newState;
    }
    /**
     * Atomically sets synchronization state to the given updated
     * value if the current state value equals the expected value.
     * This operation has memory semantics of a {@code volatile} read
     * and write.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that the actual
     *         value was not equal to the expected value.
     */
    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

利用AQS實現自定義鎖

一:首先建立一個類實現Lock介面,它有6個方法需要實現

  • lock():加鎖(不成功進入阻塞佇列等待)
  • lockInterruptibly():是否加鎖可打斷
  • tryLock()://加鎖(不成功不會進入阻塞佇列等待,可以去做其他事情)
  • tryLock(long time,TimeUnit unit):加鎖(規定時間內未獲得則放棄加鎖)
  • unlock():釋放鎖
  • newCondition():建立條件變數

二:建立一個內部類,繼承AbstractQueuedSynchronizer

可以根據需求重寫具體方法,總共有5種方法

  • isHeldExclusively():該執行緒是否正在獨佔資源。只有用到condition才需要去實現它。
  • tryAcquire(int):獨佔方式。嘗試獲取資源,成功則返回true,失敗則返回false。
  • tryRelease(int):獨佔方式。嘗試釋放資源,成功則返回true,失敗則返回false。
  • tryAcquireShared(int):共用方式。嘗試獲取資源。負數表示失敗;0表示成功,但沒有剩餘可用資源;正數表示成功,且有剩餘資源。
  • tryReleaseShared(int):共用方式。嘗試釋放資源,如果釋放後允許喚醒後續等待結點返回true,否則返回false。

三:我需要自定義一個獨佔鎖不可重入具有變數條件的鎖

分析

  • 獨佔鎖:AQS同步器中需要重寫獨佔方式的獲取資源tryAcquire(int)和釋放資源tryRelease(int)方法
  • 不可重入:AQS同步器需要實現isHeldExclusively():
  • 具有條件變數:AQS同步器中 return new ConditionObject();

具體程式碼如下

//自定義鎖(不可重入)(獨佔鎖)(條件變數)
class MyLock implements Lock{
    //內部類,AQS同步器類
    class MySync extends AbstractQueuedSynchronizer{
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0,1)){
                System.out.println("獲得鎖成功");
                //加上了鎖,並設定owner為當前執行緒
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            System.out.println("獲得鎖失敗");
            return false;
        }
 
        @Override
        protected boolean tryRelease(int arg) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
 
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
 
        public Condition newCondition(){
            return new ConditionObject();
        }
    }
 
    private MySync mySync = new MySync();
 
    @Override //加鎖(不成功進入阻塞佇列等待)
    public void lock() {
        mySync.acquire(1);
    }
 
    @Override //加鎖可打斷
    public void lockInterruptibly() throws InterruptedException {
        mySync.acquireInterruptibly(1);
    }
 
    @Override //加鎖(不成功不會進入阻塞佇列等待,可以去做其他事情)
    public boolean tryLock() {
        return mySync.tryAcquire(1);
    }
 
    @Override //嘗試加鎖 帶時間
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return mySync.tryAcquireNanos(1,unit.toNanos(time));
    }
 
    @Override //釋放鎖
    public void unlock() {
        mySync.release(1);
    }
 
    @Override //建立條件變數
    public Condition newCondition() {
        return mySync.newCondition();
    }
}

到此這篇關於Java利用AQS實現自定義鎖的文章就介紹到這了,更多相關Java AQS實現自定義鎖內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com