JUC10 利用AQS實現(xiàn)一個自己的Latch門門
11-8 DIY一次性門閂
利用 AQS實現(xiàn)一個自己的Latch門門

AQS用法
第一步 : 寫一個類,想好協(xié)作的邏輯,實現(xiàn) 獲取 / 釋放 方法。
第二步 : 內(nèi)部寫一個 Sync類繼承AbstractQueuedSynchronizer
第三步 : 根據(jù)是否 獨占 來重寫 tryAcquire / tryRelease 或 tryAcquireShared (int acquires)和 tryReleaseShared (intreleases)等方法,在之前寫的獲取/釋放方法中調(diào)用AQS的acquire/release或者Shared方法
11-8-1 實現(xiàn)獲取 /釋放方法
public void signal() {sync.releaseShared(0);}public void await() {sync.acquireShared(0);}
11-8-1-1 await()
l 起初門閂是關(guān)閉的 , 多個線程請求來了以后, 因為門閂是關(guān)閉的, 所以調(diào)用者調(diào)用await()方法, 則會進行阻塞, 進入等待狀態(tài)
l 直到后續(xù)有一個線程調(diào)用了 signal()方法, 則相當(dāng)于將門閂打開, 此前陷入等待的線程都會被釋放
l 我們內(nèi)部使用 AQS的state來表示這個門是否被打開
0: 代表默認狀態(tài), 門關(guān)閉1: 門打開
private class Sync extends AbstractQueuedSynchronizer {protected int tryAcquireShared(int arg) {return (getState() == 1) ? 1 : -1;}protected boolean tryReleaseShared(int arg) {setState(1);return true;}}
分析等待方法
public void await() {sync.acquireShared(0);}
sync .acquireShared( 0 ); 方法是使用 AQS的一個基本規(guī)則, 如果使用AQS來實現(xiàn)一個線程協(xié)作器的話, 而且是一個共享鎖就應(yīng)該去調(diào)用 sync .acquireShared( 0 )
sync .acquireShared( 0 )
public final void acquireShared(int arg) {if (tryAcquireShared(arg) < 0)// 去排隊doAcquireShared(arg);}
其中的 tryAcquireShared 方法已經(jīng)被我們重寫
protected int tryAcquireShared(int arg) {return (getState() == 1) ? 1 : -1;}
==1, 門打開
<0, 門關(guān)閉
11-8-1-2 signal()
打開門閂的意味著就是將 stat e 的值修改為 1
public void signal() {sync.releaseShared(0);}
public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) {doReleaseShared();return true;}return false;}
同樣會調(diào)用 releaseShared 方法 , releaseShared 是我們自己實現(xiàn)的
protected boolean tryReleaseShared(int arg) {setState(1);return true; // 返回true代表將之前的線程都喚醒了}
11-8-2 OneShotLatch
自己用 AQS實現(xiàn)一個簡單的線程協(xié)作器。
OneShotLatch類的代碼來自《Java并發(fā)編程實戰(zhàn)》書
public class OneShotLatch {private final Sync sync = new Sync();public static void main(String[] args) throws InterruptedException {OneShotLatch oneShotLatch = new OneShotLatch();for (int i = 0; i < 10; i++) {new Thread(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName() + "嘗試獲取latch,獲取失敗那就等待");oneShotLatch.await();System.out.println("開閘放行" + Thread.currentThread().getName() + "繼續(xù)運行");}}).start();}Thread.sleep(5000);oneShotLatch.signal();new Thread(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName() + "嘗試獲取latch,獲取失敗那就等待");oneShotLatch.await();System.out.println("開閘放行"+ Thread.currentThread().getName()+"繼續(xù)運行");}}).start();}public void signal() {sync.releaseShared(0);}public void await() {sync.acquireShared(0);}private class Sync extends AbstractQueuedSynchronizer {protected int tryAcquireShared(int arg) {return (getState() == 1) ? 1 : -1;}protected boolean tryReleaseShared(int arg) {setState(1);return true;}}}
運行結(jié)果 :

近期熱文
-
JUC1 線程池【治理線程的最大法寶】線程池簡介+增加線程池
- JUC2 線程池【治理線程的最大法寶】keepAliveTime+內(nèi)存溢出+newSingleThreadExecutor
- JUC3 線程池【治理線程的最大法寶】對比線程池 收服線程池
- JUC 4 線程池【治理線程的最大法寶】鉤子方法 Executor相關(guān)類 線程池狀態(tài)
- JUC5 ThreadLocal一網(wǎng)打盡(1)
- JUC6 ThreadLocal一網(wǎng)打盡 (2)
- JUC7 AQS, Semaphore和AQS
- JUC8 AQS三要素及簡要分析
- JUC9 AQS的許可證頒發(fā)、利用AQS實現(xiàn)獨占鎖
參考資料
1 | JUC
責(zé)編 | 小耶哥
本期作者 | 小耶哥
平臺建設(shè)及技術(shù)支持 | 小耶哥
