Java利用AQS實現自定義鎖
什麼是AQS
AQS(AbstractQueuedSynchronizer),中文名抽象隊列同步器
AQS定義瞭一套多線程訪問共享資源的同步器框架,主要用來自定義鎖和同步器
AQS原理
AQS 核心思想:
- 如果被請求的共享資源空閑,則將當前請求資源的線程設置為有效的工作線程,並且將共享資源設置為鎖定狀態。
- 如果被請求的共享資源被占用,將暫時獲取不到鎖的線程加入到阻塞隊列中,等待被喚醒和鎖的分配
實現核心思想的的隊列:CLH隊列
CLH隊列是一個虛擬的雙向隊列,AQS 是將每條請求共享資源的線程封裝成一個 CLH 鎖隊列的一個結點(Node)來實現鎖的分配。
共享資源用 volatile 關鍵詞修飾,保證線程間的可見性
/** * The synchronization state. */ private volatile int state;
0狀態表示空閑,1狀態或以上表示不空閑
共享資源(state)的訪問方式有三種:
- getState() 獲得共享資源狀態
- setState() 設置共享資源狀態
- 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!
推薦閱讀:
- Java 多線程並發ReentrantLock
- Java多線程之深入理解ReentrantLock
- 並發編程之Java內存模型鎖的內存語義
- Java 基於AQS實現自定義同步器的示例
- Java並發編程之ReentrantLock實現原理及源碼剖析