日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

简单的了解一下AQS吧

發(fā)布時(shí)間:2024/4/13 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简单的了解一下AQS吧 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是AQS

AQS,即AbstractQueuedSynchronizer,是一套定義了多線程訪問共享資源的同步器框架。在JDK的并發(fā)包中很多類都是基于AQS進(jìn)行實(shí)現(xiàn)的,比如ReentrantLock,CountDownLatch等。

AQS中的設(shè)計(jì)模式

如果單單只是看AQS類中的代碼的haul可能會(huì)產(chǎn)生很多疑惑,因?yàn)轭愔泻芏喾椒ǘ际侵挥蟹椒w,具體的實(shí)現(xiàn)需要到子類中才能看到。

模板方法模式

在我們平常的開發(fā)中會(huì)經(jīng)常遇到一個(gè)問題,當(dāng)我們接到一個(gè)需求時(shí),在整理大體思路時(shí)會(huì)很清晰。但是當(dāng)實(shí)際實(shí)現(xiàn)的時(shí)候會(huì)發(fā)現(xiàn)問題很多,有些步驟實(shí)現(xiàn)是沒有辦法確定下來的。會(huì)根據(jù)不同的需求進(jìn)行更改。

這種邏輯流程確定,但是具體實(shí)現(xiàn)可能不同的問題可以通過模板方法模式來解決。

所謂的模板方法模式就是定義一個(gè)操作的流程骨架,確定調(diào)用流程。但是具體的實(shí)現(xiàn)則交給子類去完成。模板方法模式就是利用了面向?qū)ο笾械亩鄳B(tài)特性。

在模板方法模式中有兩個(gè)重要的角色,一個(gè)是抽象模板類,另一個(gè)就是具體的實(shí)現(xiàn)類。

抽象模板類

抽象模板類用于定義業(yè)務(wù)流程,在該類中定義了一系列完成業(yè)務(wù)所需的方法。能夠確定的方法可以在抽象類中實(shí)現(xiàn)邏輯。不能確定的只是定義好方法,具體的實(shí)現(xiàn)由子類完成。

以AQS舉例,AbstractQueuedSynchronizer被定義為抽象類,其中一部分方法只是定義了方法體:

protected boolean tryAcquire(int arg) {throw new UnsupportedOperationException();}protected boolean tryRelease(int arg) {throw new UnsupportedOperationException();} 復(fù)制代碼

盡管這部分方法并沒有提供具體的實(shí)現(xiàn),但是AQS中的其他方法還是直接調(diào)用了該方法。

public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}public final void acquireInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();if (!tryAcquire(arg))doAcquireInterruptibly(arg);} 復(fù)制代碼

跟句抽象類的特性,如果要使用這些方法的話就必須在子類繼承AQS并實(shí)現(xiàn)這些抽象方法。這樣的方法類被稱為模板類。

實(shí)現(xiàn)類

模板類的抽象方法的邏輯實(shí)現(xiàn)是在子類中完成的,不同的子類可以根據(jù)具體的需求進(jìn)行個(gè)性化的實(shí)現(xiàn)。

比如ReentrantLock中Sync和FairSync對(duì)于tryAcquire的實(shí)現(xiàn):

Sync:

protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;} 復(fù)制代碼

FairSync:

protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {//這里多了一次是否存在等待更長(zhǎng)時(shí)間線程的判斷if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;} 復(fù)制代碼

這樣的類被稱為實(shí)現(xiàn)類。

AQS中的模板方法

AQS就是典型的應(yīng)用模板方法模式的例子,如果我們要通過AQS來實(shí)現(xiàn)一個(gè)同步類。那么我們需要實(shí)現(xiàn)以下方法:

tryAcquire(int) tryRelease(int) tryAcquireShared(int) tryReleaseShared(int) isHeldExclusively() 復(fù)制代碼

部分參數(shù)解析

state

state參數(shù)是非常重要的一個(gè)參數(shù),AQS的鎖狀態(tài)就是依賴于改參數(shù)實(shí)現(xiàn)的。

AQS中對(duì)鎖的操作是利用CAS進(jìn)行實(shí)現(xiàn),而cas主要操作的對(duì)象就是state參數(shù)。當(dāng)state=0時(shí)表示可以獲取鎖,而當(dāng)state!=0時(shí)則表示已經(jīng)進(jìn)行了加鎖操作。

可重入鎖的實(shí)現(xiàn)也依賴于該參數(shù),當(dāng)持有鎖的線程再次獲取一次鎖時(shí)便將state的值加一,而每一次釋放一次鎖則進(jìn)行減一操作,只有當(dāng)state=0時(shí)才算是釋放鎖完畢。

Node

static final class Node {static final Node SHARED = new Node();static final Node EXCLUSIVE = null;static final int CANCELLED = 1;static final int SIGNAL = -1;static final int CONDITION = -2;static final int PROPAGATE = -3;volatile int waitStatus;volatile Node prev;volatile Node next;volatile Thread thread;Node nextWaiter; } 復(fù)制代碼

Node用于保存獲取鎖失敗時(shí)

Node.SHARED和Node.EXCLUSIVE

在AQS的具體實(shí)現(xiàn)中存在兩種不同模式的鎖:排他鎖和共享鎖

一般共享鎖主要用于讀操作,表示讀操作可以是多個(gè)線程同時(shí)進(jìn)行,而不會(huì)阻塞;排他鎖主要用于寫操作,會(huì)進(jìn)行阻塞

而排他鎖和共享鎖的實(shí)現(xiàn)就依賴于Node.SHARED和Node.EXCLUSIVE區(qū)分。比如ReentrantReadWriteLock。

waitStatus

waitStatus用于表示當(dāng)前節(jié)點(diǎn)所處的狀態(tài)。

  • 初始狀態(tài):節(jié)點(diǎn)初始狀態(tài)值被初始化為0,如果是通過condition注冊(cè)的節(jié)點(diǎn)其初始狀態(tài)為-2(CONDITION)
  • CANCELLED:static final int CANCELLED = 1;由于超時(shí)或者中斷等原因使得當(dāng)前節(jié)點(diǎn)被標(biāo)記位取消狀態(tài)。一般來說被標(biāo)記為取消狀態(tài)的節(jié)點(diǎn)不會(huì)再去競(jìng)爭(zhēng)鎖并且不能轉(zhuǎn)換為其他狀態(tài)。
  • SIGNAL:static final int SIGNAL = -1;當(dāng)前節(jié)點(diǎn)的后繼節(jié)點(diǎn)通過park被阻塞(或者將要被阻塞)。那么在當(dāng)前節(jié)點(diǎn)釋放或者取消時(shí)需要通過unpark取消阻塞。
  • CONDITION:static final int CONDITION = -2;將節(jié)點(diǎn)放在condition隊(duì)列中是需要標(biāo)識(shí)其狀態(tài)為CONDITION。
  • PROPAGATE:static final int PROPAGATE = -3;該狀態(tài)值用于在共享狀態(tài)下,當(dāng)共享狀態(tài)的鎖被釋放后,該操作會(huì)被傳播到其他節(jié)點(diǎn)。

prev next

prev和next分別用于記錄前驅(qū)節(jié)點(diǎn)和后繼節(jié)點(diǎn)

重要方法解析

tryAcquire

protected boolean tryAcquire(int arg);

tryAcquire字面意思很明確,就是嘗試獲取鎖。獲取鎖成功則返回true,獲取鎖失敗則將該線程放入等待隊(duì)列中,等待占用資源的線程被釋放。

在JDK中明確定義tryAcquire方法用于獲取的處于獨(dú)占模式下的鎖。如果不是獨(dú)占模式則拋出異常UnsupportedOperationException。

該方法需要被重寫。

該方法共享模式版本為protected int tryAcquireShared(int arg).

tryRelease

protected boolean tryRelease(int arg);

該方法用于在獨(dú)占模式下通過cas嘗試設(shè)置state狀態(tài)值,用于釋放鎖操作。

修改值成功則返回true。如果不是獨(dú)占模式則拋出異常UnsupportedOperationException。

該方法需要被重寫。

該方法的共享模式方法為protected boolean tryReleaseShared(int arg)。

isHeldExclusively

該方法用于來判斷是否當(dāng)前線程正在以獨(dú)占模式進(jìn)行同步操作。

setState和compareAndSetState

setState和compareAndSetState兩個(gè)方法都是對(duì)state參數(shù)的值進(jìn)行設(shè)置。

不同之處在于compareAndSetState主要用于獲取鎖時(shí)修改狀態(tài)值,因?yàn)楂@取鎖時(shí)存在競(jìng)爭(zhēng)問題所以需要原子操作獲取。

而setState操作用于在釋放鎖是修改state的值,釋放鎖時(shí)只有持有鎖的線程會(huì)進(jìn)行釋放,不存在競(jìng)爭(zhēng)問題,不需要原子操作。

動(dòng)手實(shí)現(xiàn)一個(gè)同步類

現(xiàn)在我們來實(shí)現(xiàn)一個(gè)我們自己的同步類,一個(gè)不可重入的獨(dú)占鎖。

public class MyLock implements Lock {static class Sync extends AbstractQueuedSynchronizer{@Overrideprotected boolean tryAcquire(int arg) {//這里只有當(dāng)state=0時(shí)才能獲取鎖 表示該同步類不可重入if(compareAndSetState(0,1)){setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}@Overrideprotected boolean tryRelease(int arg) {if(getState()!=1){//無法再被釋放throw new IllegalMonitorStateException();}setState(0);setExclusiveOwnerThread(null);return true;}@Overrideprotected boolean isHeldExclusively() {return getState()==1 || getExclusiveOwnerThread()==Thread.currentThread();}// 返回一個(gè)Condition,每個(gè)condition都包含了一個(gè)condition隊(duì)列Condition newCondition() {return new ConditionObject();}}private final Sync sync = new Sync();@Overridepublic void lock() {sync.acquire(1);}@Overridepublic void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}@Overridepublic boolean tryLock() {return sync.tryAcquire(1);}@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return sync.tryAcquireNanos(1,unit.toNanos(time));}@Overridepublic void unlock() {sync.release(0);}@Overridepublic Condition newCondition() {return sync.newCondition();} }復(fù)制代碼

即使我們并不知道AQS的內(nèi)部實(shí)現(xiàn),只需要了解AQS中的幾個(gè)方法作用并在子類中重寫這些方法就能設(shè)計(jì)出一個(gè)簡(jiǎn)單的同步類。

轉(zhuǎn)載于:https://juejin.im/post/5cb6ab10e51d456e7f0ba56b

總結(jié)

以上是生活随笔為你收集整理的简单的了解一下AQS吧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。