Java利用AQS實現自定義鎖

什麼是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實現自定義鎖內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: