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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java并发编程—AQS原理分析

發(fā)布時(shí)間:2024/4/15 java 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java并发编程—AQS原理分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

一、AQS原理簡述

二、自定義獨(dú)占鎖及共享鎖

三、鎖的可重入性

四、鎖的公平性

五、驚群效應(yīng)


AQS全稱AbstractQueuedSynchronizer,它是實(shí)現(xiàn)?JCU包中幾乎所有的鎖、多線程并發(fā)以及線程同步器等重要組件的基石, 其核心思想是基于volatile int state這樣的一個(gè)屬性同時(shí)配合Unsafe工具對(duì)其原子性的操作來實(shí)現(xiàn)對(duì)當(dāng)前鎖的狀態(tài)進(jìn)行修改

一、AQS原理簡述

AQS內(nèi)部維護(hù)著一個(gè)FIFO的CLH隊(duì)列(無鎖隊(duì)列:Concurrent Lock-free FIFO),該隊(duì)列的基本結(jié)構(gòu)如下:

1.1、Node節(jié)點(diǎn)

AQS中使用Node來表示CLH隊(duì)列的每個(gè)節(jié)點(diǎn),源碼如下:

static final class Node {//表示共享模式(共享鎖)static final Node SHARED = new Node();//表示獨(dú)占模式(獨(dú)占鎖)static final Node EXCLUSIVE = null;//表示線程已取消static final int CANCELLED = 1;//表示當(dāng)前結(jié)點(diǎn)的后繼節(jié)點(diǎn)需要被喚醒static final int SIGNAL = -1;//線程(處在Condition休眠狀態(tài))在等待Condition喚醒static final int CONDITION = -2;//表示鎖的下一次獲取可以無條件傳播,在共享模式頭結(jié)點(diǎn)有可能處于這種狀態(tài)static final int PROPAGATE = -3;//線程等待狀態(tài)volatile int waitStatus;//當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)volatile Node prev;//當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)volatile Node next;//當(dāng)前節(jié)點(diǎn)所代表的的線程volatile Thread thread;//可以理解為當(dāng)前是獨(dú)占模式還是共享模式Node nextWaiter;//如果節(jié)點(diǎn)在共享模式下等待,則返回true。final boolean isShared() {return nextWaiter == SHARED;}//獲取前一個(gè)節(jié)點(diǎn)final Node predecessor() throws NullPointerException {Node p = prev;if (p == null)throw new NullPointerException();elsereturn p;}...}

1.2、入隊(duì)

如果當(dāng)前線程通過CAS獲取鎖失敗,AQS會(huì)將該線程以及等待狀態(tài)等信息打包成一個(gè)Node節(jié)點(diǎn),并將其加入同步隊(duì)列的尾部,同時(shí)將當(dāng)前線程掛起。總體流程圖如下。

獲取鎖失敗并添加節(jié)點(diǎn)到同步隊(duì)列尾部的操作

1.3、出隊(duì)

當(dāng)釋放鎖時(shí),執(zhí)行出隊(duì)操作及喚醒后繼節(jié)點(diǎn)。總體流程圖如下。

釋放鎖時(shí)的移除節(jié)點(diǎn)操作

?

1.4、同步狀態(tài)管理

或許對(duì)圖中的同步器有所疑惑。它到底是什么?其實(shí)很簡單,它就是給首尾兩個(gè)節(jié)點(diǎn)加上volatile同步域,如下。

private transient volatile Node head; private transient volatile Node tail; private volatile int state;

上面三個(gè)變量是AQS中非常重要的三個(gè)變量,前面兩個(gè)變量好理解,下面就來說一下state變量,該變量是一個(gè)計(jì)數(shù)器,在獨(dú)占鎖情況下,獲取鎖后,state的值就會(huì)為1,釋放鎖時(shí)就設(shè)置為0(這種鎖屬于不可重入鎖);在共享鎖情況下,每一個(gè)線程獲取到鎖,就會(huì)state++,釋放鎖時(shí)就state–;在可重入鎖情況下(獲取的鎖都是同一把鎖),每獲取一次鎖會(huì)state++,釋放鎖時(shí)state–。

protected final int getState() {return state; } protected final void setState(int newState) {state = newState; } //使用CAS protected final boolean compareAndSetState(int expect, int update) {// See below for intrinsics setup to support thisreturn unsafe.compareAndSwapInt(this, stateOffset, expect, update); }

二、自定義獨(dú)占鎖及共享鎖

通過上一節(jié)的講解,想必對(duì)AQS有了一定的了解,下面就通過AQS來實(shí)現(xiàn)一個(gè)獨(dú)占鎖及共享鎖。AQS非常強(qiáng)大,只需要重寫tryAcquire、tryRelease這兩個(gè)方法就可以實(shí)現(xiàn)一個(gè)獨(dú)占鎖。源碼如下:

public class SingleLock implements Lock {//自定義的獨(dú)占鎖static class Sync extends AbstractQueuedSynchronizer {//獨(dú)占鎖@Overrideprotected boolean tryAcquire(int arg) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}//獨(dú)占鎖@Overrideprotected boolean tryRelease(int arg) {setExclusiveOwnerThread(null);setState(0);return true;}//判斷是是否是獨(dú)占鎖。@Overrideprotected boolean isHeldExclusively() {return getState() == 1;}Condition newCondition() {return new ConditionObject();}}private Sync sync;public SingleLock() {sync = new Sync();}//加鎖@Overridepublic void lock() {sync.acquire(1);}//獲取可中斷鎖@Overridepublic void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}//獲取鎖,可能失敗@Overridepublic boolean tryLock() {return sync.tryAcquire(1);}//在time時(shí)間內(nèi)不能獲取鎖則失敗@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return sync.tryAcquireNanos(1, unit.toNanos(time));}//釋放鎖@Overridepublic void unlock() {sync.release(1);}//Condition來實(shí)現(xiàn)阻塞喚醒機(jī)制@Overridepublic Condition newCondition() {return sync.newCondition();} }

很簡單的代碼就實(shí)現(xiàn)了一個(gè)獨(dú)占鎖,SingleLock擁有ReentrantLock的大部分功能,并且用法一模一樣。是不是很簡單…JUC包中提供的閉鎖(CountDownLatch)及信號(hào)量(Semaphore)就是典型的共享鎖的實(shí)現(xiàn)。共享鎖的實(shí)現(xiàn)也很簡單,需要重寫tryAcquireShared、tryReleaseShared這兩個(gè)方法。下面就來實(shí)現(xiàn)一個(gè)共享鎖。代碼如下:

public class ShareLock implements Lock {static class Sync extends AbstractQueuedSynchronizer {private int count;Sync(int count) {this.count = count;}@Overrideprotected int tryAcquireShared(int arg) {for (; ; ) {int current = getState();int newCount = current - arg;if (newCount < 0 || compareAndSetState(current, newCount)) {return newCount;}}}@Overrideprotected boolean tryReleaseShared(int arg) {for (; ; ) {int current = getState();int newCount = current + arg;if (compareAndSetState(current, newCount)) {return true;}}}Condition newCondition() {return new ConditionObject();}}private int count;private Sync sync;public ShareLock(int count) {this.count = count;sync = new Sync(count);}@Overridepublic void lock() {sync.acquireShared(1);}@Overridepublic void lockInterruptibly() throws InterruptedException {sync.acquireSharedInterruptibly(1);}@Overridepublic boolean tryLock() {return sync.tryAcquireShared(1) >= 0;}@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(time));}@Overridepublic void unlock() {sync.releaseShared(1);}@Overridepublic Condition newCondition() {return sync.newCondition();} }

ShareLock允許count個(gè)線程同時(shí)獲取鎖,它的實(shí)現(xiàn)也很簡單吧。通過上面這兩個(gè)例子,我們就可以按照自己需求來實(shí)現(xiàn)不同的鎖,但JUC包中提供的類基本上能滿足絕大部分需求了。

三、鎖的可重入性

SingleLock是我們自己實(shí)現(xiàn)的一種獨(dú)占鎖,但如果把它用在遞歸中,就會(huì)產(chǎn)生死鎖。因?yàn)镾ingleLock不具備可重入性。那么該如何實(shí)現(xiàn)可重入性尼?來看ReentrantLock的實(shí)現(xiàn)。

final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}//可重入性的實(shí)現(xiàn),如果當(dāng)前線程已拿到鎖else if (current == getExclusiveOwnerThread()) {//狀態(tài)加1int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");//重新設(shè)置狀態(tài)setState(nextc);return true;}return false;}

可以發(fā)現(xiàn)可重入性的實(shí)現(xiàn)還是蠻簡單的,首先判斷當(dāng)前線程是不是已經(jīng)拿到鎖,如果已經(jīng)拿到鎖就將state的值加1。可重入性這一點(diǎn)非常重要,否則會(huì)產(chǎn)生不必要的死鎖問題,Synchronize也具備可重入性。

四、鎖的公平性

SingleLock屬于一個(gè)非公平鎖,那么如何實(shí)現(xiàn)公平鎖尼?其實(shí)這更簡單,只需要加個(gè)判斷即可。來看ReentrantLock的公平鎖的實(shí)現(xiàn)。

protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {//如果當(dāng)前線程之前還有節(jié)點(diǎn)則hasQueuedPredecessors返回true,就不會(huì)去競(jìng)爭鎖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;}

hasQueuedPredecessors就是判斷鎖是否公平的關(guān)鍵,如果在當(dāng)前線程之前還有排隊(duì)的線程就返回true,這時(shí)候當(dāng)前線程就不會(huì)去競(jìng)爭鎖。從而保證了鎖的公平性。

五、驚群效應(yīng)

在使用wait/notify/notifyAll時(shí),喚醒線程都是使用notifyAll來喚醒線程,因?yàn)閚otify無法喚醒指定線程,從而可能導(dǎo)致死鎖。但使用notifyAll也有一個(gè)問題,那就是當(dāng)大量線程來獲取鎖時(shí),就會(huì)產(chǎn)生驚群效應(yīng),大量的競(jìng)爭必然造成資源的劇增和浪費(fèi),因此終究只能有一個(gè)線程競(jìng)爭成功,其他線程還是要老老實(shí)實(shí)的回去等待。而AQS的FIFO的等待隊(duì)列給解決在鎖競(jìng)爭方面的驚群效應(yīng)問題提供了一個(gè)思路:保持一個(gè)FIFO隊(duì)列,隊(duì)列每個(gè)節(jié)點(diǎn)只關(guān)心其前一個(gè)節(jié)點(diǎn)的狀態(tài),線程喚醒也只喚醒隊(duì)頭等待線程

【參考資料】
深入學(xué)習(xí)java同步器AQS
淺談Java并發(fā)編程系列(九)—— AQS結(jié)構(gòu)及原理分析
Java并發(fā)編程之AQS
扒一扒ReentrantLock以及AQS實(shí)現(xiàn)

總結(jié)

以上是生活随笔為你收集整理的Java并发编程—AQS原理分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 欧美日韩在线不卡 | 久久国产精品无码一级毛片 | 国产一区二区三区在线观看视频 | 久久天天东北熟女毛茸茸 | 91夫妻论坛 | 亚洲精品视频三区 | 国产精品久久久久久免费 | 国产精品你懂的 | 黄色污网站在线观看 | 亚洲色图国产 | 艹少妇视频 | 成人精品视频一区二区三区尤物 | 91精品久久久久久久久久久 | 亚洲精品国产99 | 免费黄色大片 | 德国性经典xxxx性hd | 99re这里有精品 | 情五月 | 精品人妻二区中文字幕 | 中文字幕一二三区 | 亚洲资源网 | 欧美日韩国产第一页 | 欧美日韩在线观看免费 | 久久99热人妻偷产国产 | 国产freexxxx性播放麻豆 | 国产一区二区三区视频免费观看 | 日韩一区电影 | 男人网站在线观看 | 五月综合色 | 午夜a视频 | 超碰www| 蜜色av| 日韩一级视频在线观看 | 亚洲毛片在线播放 | 久久精品视频中文字幕 | 国产成人午夜精品无码区久久 | 99久久久成人国产精品 | 深夜国产视频 | 精品中文字幕在线播放 | 亚洲图片偷拍区 | 中文日韩字幕 | 日韩精品导航 | 亚洲国内精品 | 色骚综合| 亚洲骚片 | 九九热视频在线免费观看 | 欧美最猛性xxxxx(亚洲精品) | 一区二区免费在线观看视频 | 男人添女人下部高潮全视频 | 蜜桃视频在线观看一区 | 久草免费av | 天天插夜夜爽 | 国产偷人妻精品一区二区在线 | 人妻互换一二三区激情视频 | 午夜天堂影院 | 国产精品无码一区二区三区在线看 | 人体私拍套图hdxxxx | 小泽玛利亚一区二区三区在线观看 | 久操不卡 | 天天干导航 | 欧美xxxx吸乳 | 成人在线免费小视频 | 日韩免费av在线 | 天天色婷婷 | 九九激情视频 | 麻豆天天躁天天揉揉av | 欧美三级特黄 | 国产精品白嫩极品美女 | 午夜视频www| 亚洲欧美成人一区二区 | 成人h动漫精品一区二区器材 | 少妇av一区二区三区无码 | 美女啪啪无遮挡 | 亚洲精品中文无码AV在线播放 | 国产8区 | 国产成人a亚洲精v品无码 | 亚洲色图清纯唯美 | 国产另类在线 | 伊人色图 | 日本三级一区二区 | 中文字幕欲求不满 | 欧美日韩成人在线播放 | 亚洲视频在线观看 | 天天干天天操天天摸 | 日本激情在线 | 91看片国产 | 国产精品久久久久久 | 久久无毛 | 日韩精品极品视频免费观看 | 99久久精品日本一区二区免费 | 久久高清av| 美日韩中文字幕 | 成人三级视频 | 亚洲一区二区三区电影 | 黄视频网站在线 | 黄a免费网络 | 日本男女激情视频 | 粉嫩av一区二区三区四区五区 | 免费黄色在线 |