怎麼利用AbstractQueuedSynchronizer實現自定義同步元件?
文章目錄
實現步驟
1. 確定訪問模式。是共享的還是獨佔的?是否需要公平?
實現內部靜態類(常用類名為Sync)繼承AbstractQueuedSynchronizer。根據訪問模式確定重寫哪種方法:
可重寫的方法:
方法名稱 | 描述 |
---|---|
protected boolean tryAcquire(int arg) | 獨佔式獲取同步狀態,實現該方法需要查詢當前狀態並判斷同步狀態是否符合預期,然後再進行CAS設定同步狀態。 |
protected boolean tryRelease(int arg) | 獨佔式釋放同步狀態,等待獲取同步狀態的執行緒將有機會獲取同步狀態。 |
protected int tryAcquireShared(int arg) | 共享式獲取同步狀態,返回>=0的值,表示獲取成功,反之失敗 |
protected boolean tryReleaseShared(int arg) | 共享式釋放同步狀態 |
protected boolean isHeldExclusively() | 當前同步器是否在獨佔模式下被執行緒佔用,一般該方法表示是否被當前執行緒獨佔 |
2. 定義資源數。是確定的還是引數設定的?
在靜態內部類時一般都是用參數列示資源,在組合時會選擇繼續傳引數還是固定值。資源數也就是狀態數,個人習慣稱為資源數。
3. 組合自定義同步器。是否需要使用模板方法?
這裡比較靈活,有的實現有呼叫有的沒有。實現自定義同步元件時,可以呼叫同步器提供的模板方法:
方法 | 描述 |
---|---|
void acquire(int arg) | 獨佔式獲取同步狀態,如果當前執行緒獲取同步狀態成功,則由該方法返回,否則,將會進入同步佇列等待,該方法會呼叫重寫的tryAcquire(int arg)方法 |
void acquireInterruptibly(int arg) | 與acquire(int arg)相同,但該方法響應中斷,當前執行緒未獲取到同步狀態而進入同步佇列中,如果當前執行緒被中斷,則該方法會丟擲InterruptedException並返回 |
boolean tryAcquireNanos(int arg,long nanos) | 在acquireInterruptibly(int arg)上增加了超時方法,超時時間內獲取返回true,否則false |
void acquireShared(int arg) | 共享式獲取同步狀態,和獨佔式區別在同一時刻可以有多個執行緒獲取到同步狀態 |
void acquireSharedInterruptibly(int arg) | 和上面的方法相同但是響應中斷 |
boolean tryAcquireSharedNanos(int arg,long nanos) | 在上面方法基礎上增加了超時 |
boolean release(int arg) | 獨佔式的釋放同步狀態,該方法在釋放同步狀態之後,將同步佇列中第一個節點包含的執行緒喚醒 |
boolean releaseShared(int arg) | 共享式的釋放同步狀態 |
Collection getQueuedThreads | 獲取等待在同步佇列上的執行緒集合 |
用CountDownLatch驗證
確定訪問模式
CountDownLatch支援多執行緒訪問,但是對資源數做限制。所以首先是共享的。就CountDownLatch功能來說,執行緒的先後順序也並不重要,所以不需要公平。
可以看到,這裡實現的靜態內部類繼承了AQS並重寫了關於shared(共享的)方法。
確定資源數
CountDownLatch的資源數不確定,由傳入自定義同步元件的引數決定。
組合自定義同步器
這裡特別靈活。像CountDownlatch只是進行了一層簡單的封裝。
用Semaphore驗證
確定訪問模式
Semaphore支援多執行緒訪問,但是對資源數做限制。所以首先是共享的。Semaphore可以是公平的。
可以看到,這裡實現的靜態內部類繼承了AQS並重寫了關於shared(共享的)方法。需要注意這裡reducePermits和drainPermits不是重寫的方法,而是自定義的方法。
這一段程式碼實現了公平機制,其中:
公平和非公平的區別在於這段程式碼:
if (hasQueuedPredecessors())
return -1;
這是AQS裡的方法,用來判斷當前執行的執行緒是否位於佇列頭部。因為佇列是後進先出的,所以頭結點是最先進去的,也就是公平的定義。
確定資源數
Semaphore的資源數不確定,由傳入自定義同步元件的引數決定。
組合自定義同步器
Semaphore在組合時就複雜了非常多,但是還是圍繞shared體系的方法,所以一開始就要確定是否是共享的。
自定義同步元件Mutex(獨佔鎖)
ReentrantLock這裡不展開講了,首先它是獨佔的,然後也可以是公平的,資源數恆定為1。
獨佔鎖也就是在同一時刻只有一個執行緒獲取到鎖,而其他請求鎖的執行緒只能在同步佇列中排隊~這裡用實現自定義同步元件Mutex為例:
確定訪問模式
獨佔鎖執行緒獨佔資源,所以用非shared那套。可以實現公平也可以不實現公平,這裡偷個懶實現非公平的。
確定資源數
在鎖這裡感覺資源稱為狀態好點ヽ( ̄▽ ̄)و。兩個狀態0,1。0代表獲取1個執行緒獲取到了同步資源,1代表沒有執行緒獲取到資源。
組合自定義同步器
這裡由於獨佔鎖也是鎖,可以作為一種Lock的實現,實現Lock。這一步更多的是思考這個自定義同步器要實現什麼功能。對於大部分的功能類庫中都有實現。
以下是完整程式碼:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class Mutex implements Lock {
private final Sync sync = new Sync();
private static class Sync extends AbstractQueuedSynchronizer {
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
} else return false;
}
@Override
protected boolean tryRelease(int arg) {
if (getState() == 0) {
throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
Condition newCondition(){ return new ConditionObject();}
}
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean isLocked() {
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads() throws InterruptedException{
return sync.hasQueuedThreads();
}
@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();
}
}
該例項中,獨佔式Mutex是一個自定義同步元件。
參考文獻
《Java併發程式設計的藝術》
相關文章
- Qt實現自定義控制元件QT控制元件
- 自定義DropDownList控制元件的實現控制元件
- 自定義TextBox控制元件的實現控制元件
- 學習JUC原始碼(2)——自定義同步元件原始碼元件
- Android自定義控制元件之自定義ViewGroup實現標籤雲Android控制元件View
- 微信小程式Tree自定義控制元件實現微信小程式控制元件
- QT實現可拖動自定義控制元件QT控制元件
- Java 中佇列同步器 AQS(AbstractQueuedSynchronizer)實現原理Java佇列AQS
- 如何利用 Netty 實現自定義協議通訊?Netty協議
- Android 自定義控制元件實現刮刮卡效果 真的就只是刮刮卡麼Android控制元件
- 自定義View:自定義屬性(自定義按鈕實現)View
- React Native 實現自定義下拉重新整理元件React Native元件
- 多引數路由中巧妙利用自定義鍵名實現需求路由
- 如何利用微狗仔實現微信自定義分享卡片連結
- 利用husky實現前端專案自定義規範校驗前端
- android利用RecyclerView+自定義View實現城市選擇介面AndroidView
- Tomcat怎麼實現非同步ServletTomcat非同步Servlet
- 自定義View:畫布實現自定義View(折線圖的實現)View
- Net 實現自定義Aop
- EventSource的自定義實現
- 微信分享自定義實現
- 自定義來電秀怎麼實現?Android 來電秀原始碼分析Android原始碼
- 栗子——自定義EditText實現右下角計數控制元件控制元件
- win10怎麼開啟自定義縮放 win10怎麼自定義縮放Win10
- 簡單4步,利用Prometheus Operator實現自定義指標監控Prometheus指標
- Vue2-利用自定義指令實現按鈕許可權控制Vue
- Spring Boot 自動配置的原理、核心註解以及利用自動配置實現了自定義 Starter 元件Spring Boot元件
- Sketch怎麼自定義快捷鍵
- 華納雲:mysql怎麼自定義常量MySql
- 同步器AbstractQueuedSynchronizer淺析
- mysql和redis實時同步資料怎麼實現MySqlRedis
- Android自定義控制元件之自定義組合控制元件Android控制元件
- vue自定義全域性元件(或自定義外掛)Vue元件
- Android自定義控制元件——自定義屬性Android控制元件
- 基於 RecyclerView 實現的歌詞滾動自定義控制元件View控制元件
- 自定義SpringMVC部分實現SpringMVC
- Android自定義拍照實現Android
- Flutter自定義Banner的實現Flutter