Java并發(fā)編程-隊(duì)列同步器(AbstractQueuedSynchronizer)

章節(jié)目錄

  • Lock接口與Synchronized的區(qū)別及特性
  • 隊(duì)列同步器的接口與自定義鎖示例
  • 隊(duì)列同步器的實(shí)現(xiàn)分析

1.Lock接口與Synchronized的區(qū)別及特性

特性 描述
嘗試非阻塞性的獲取鎖 當(dāng)前線程嘗試獲取鎖(自旋獲取鎖)烙无,如果這一時(shí)刻鎖沒(méi)有被其他線程獲取到情妖,則成功獲取并持有鎖
能被中斷的獲取鎖 已獲取鎖的線程可以響應(yīng)中斷兵怯,當(dāng)獲取到鎖的線程被中斷時(shí),可以拋出中斷異常功偿,同時(shí)鎖會(huì)被釋放
超時(shí)獲取鎖 在指定的截止時(shí)間之前獲取鎖或渤,如果截止時(shí)間到了仍然沒(méi)有獲取到鎖朋魔,則返回

注意:Lock接口的實(shí)現(xiàn)基本上都是通過(guò)聚合了一個(gè)同步器的子類來(lái)完成線程訪問(wèn)控制的

隊(duì)里同步器的接口與定義鎖示例

隊(duì)列同步器定義:

隊(duì)列同步器函荣,是用來(lái)構(gòu)建鎖與其它同步組件的基礎(chǔ)框架,基本數(shù)據(jù)結(jié)構(gòu)與內(nèi)容是:
1浸踩、int state -> state 標(biāo)示同步狀態(tài)叔汁;
2、內(nèi)置的FIFO來(lái)完成獲取同步狀態(tài)的線程的排隊(duì)工作检碗。

隊(duì)列同步器使用方式

1据块、子類通過(guò)繼承同步器并實(shí)現(xiàn)它的抽象方法來(lái)管理同步狀態(tài);
2折剃、實(shí)現(xiàn)過(guò)程中對(duì)同步狀態(tài)的更改另假,通過(guò)
setState()、
setState(int newState)怕犁、
compareAndSetState(int expect,int newUpdateValue)
來(lái)進(jìn)行操作边篮,保證狀態(tài)改變時(shí)原子性的己莺、安全的;
3戈轿、實(shí)現(xiàn)同步器的子類被推薦為自定義同步組件的靜態(tài)內(nèi)部類凌受;
4、同步器可以支持獨(dú)占式的獲取同步狀態(tài)(ReentrantLock)思杯、也可以支持共享
式的獲取同步狀態(tài)(ReentrantReadWriteLock)

對(duì)于同步器的關(guān)系可以這樣理解:

  • 在鎖的實(shí)現(xiàn)中聚合同步器胜蛉,利用同步器實(shí)現(xiàn)鎖的語(yǔ)義。
  • 鎖面向使用者色乾,它定義了使用者與鎖的交互接口誊册,隱藏了實(shí)現(xiàn)細(xì)節(jié)。
  • 同步器面向的是鎖的實(shí)現(xiàn)者暖璧,它簡(jiǎn)化了鎖的實(shí)現(xiàn)方式案怯,屏蔽了同步器狀態(tài)管理、線程排隊(duì)澎办、等待與喚醒等底層操作殴泰。

2.隊(duì)列同步器的接口與自定義鎖示例

2.1 模板方法模式

同步器的設(shè)置是基于**模版方法模式**,使用者需要繼承同步器并重寫指定的方
法,隨后將同步器組合在自定義同步組件的實(shí)現(xiàn)中浮驳,并調(diào)用同步器提供的模板
方法,而這些模板方法將會(huì)調(diào)用使用者重寫的方法捞魁。

2.2 重寫同步器指定的方法

getState():獲取當(dāng)前同步狀態(tài)
setState(int newState):設(shè)置當(dāng)前同步狀態(tài)
compareAndSetState(int expect,int update): 使用CAS設(shè)置當(dāng)前的狀態(tài)至会,該方
法保證狀態(tài)設(shè)置的原子性

2.3 同步器可重寫的方法

方法名稱 描述
protected boolean tryAcquire(int arg) 獨(dú)占式獲取同步狀態(tài),實(shí)現(xiàn)該方法需要查詢當(dāng)前狀態(tài)并判斷同步狀態(tài)是否符合預(yù)期谱俭,然后再進(jìn)行CAS設(shè)置同步狀態(tài)
protected boolean tryRelease(int arg) 獨(dú)占式釋放同步狀態(tài)奉件,等待獲取同步狀態(tài)的線程將有機(jī)會(huì)獲取同步狀態(tài)(公平性獲取鎖)
protected int tryAcquireShared(int arg) 共享式獲取同步狀態(tài),返回>=0的值昆著,標(biāo)示獲取成功县貌,反之獲取失敗
protected boolean tryReleaseShared(int arg) 共享式釋放同步狀態(tài)
protected boolean isHeldExclusively() 當(dāng)前同步器是否在獨(dú)占模式下被線程占用,一般該方法表示是否被當(dāng)前線程所獨(dú)占

2.4 獨(dú)占鎖示例

package org.seckill.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 static class Sync extends AbstractQueuedSynchronizer {
        //是否處于占用狀態(tài)
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        //當(dāng)狀態(tài)為0時(shí)獲取鎖
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        //釋放鎖凑懂,將當(dāng)前狀態(tài)設(shè)置為0
        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;

        }

        //返回一個(gè)condition,每個(gè)condition中都包含了一個(gè)condition隊(duì)列
        Condition newCondition() {
            return new ConditionObject();
        }
    }

    //僅需要將操作代理到Sync上即可
    private Sync sync = new Sync();

    public void lock() {
        sync.acquire(1);//調(diào)用tryAccquire
    }

    //當(dāng)前已獲取鎖的線程響應(yīng)中斷煤痕,釋放鎖,拋出異常接谨,并返回
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);//嘗試立即獲取鎖
    }

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));//嘗試超時(shí)獲取鎖
    }

    public void unlock() {
        sync.release(1);//釋放鎖
    }

    public Condition newCondition() {
        return sync.newCondition();
    }
}

總結(jié)-實(shí)現(xiàn)同步組件的方法

1. 獨(dú)占鎖Mutex 是一個(gè)自定義同步組件摆碉,它允許同一時(shí)刻只允許同一個(gè)線程占有鎖。
2.Mutex中定義了一個(gè)私有靜態(tài)內(nèi)部類脓豪,該類繼承了同步器并實(shí)現(xiàn)了獨(dú)占式獲取和釋放同步狀態(tài)巷帝。
3.在tryAcquire(int acquires)方法中,經(jīng)過(guò)CAS設(shè)置成功(同步狀態(tài)設(shè)置為1)扫夜,則
代表獲取了同步狀態(tài)楞泼,而在tryRelease(int releases) 方法中只是將同步狀態(tài)重
置為0驰徊。

3 隊(duì)列同步器的實(shí)現(xiàn)分析

3.1 同步隊(duì)列數(shù)據(jù)結(jié)構(gòu)

  • 同步器依賴內(nèi)部的同步隊(duì)列,即一個(gè)FIFO的隊(duì)列堕阔,這個(gè)隊(duì)列由雙向鏈表實(shí)現(xiàn)棍厂。節(jié)點(diǎn)數(shù)據(jù)從 隊(duì)列尾部插入,頭部刪除印蔬。
  • node 數(shù)據(jù)結(jié)構(gòu)
   struct node {
        node prev; //節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)
        node next; //節(jié)點(diǎn)后繼節(jié)點(diǎn)
        Thread thread; //獲取同步狀態(tài)的線程
        int waitStatus;  //等待狀態(tài)
        Node nextWaiter; //等待隊(duì)列中的后繼節(jié)點(diǎn)
   }

等待隊(duì)列 后續(xù)篇章介紹到condition會(huì)有相關(guān)記錄勋桶。

同步隊(duì)列基本結(jié)構(gòu)

3.2 無(wú)法獲取到同步狀態(tài)的線程節(jié)點(diǎn)被加入到同步隊(duì)列的尾部

本質(zhì)上是采用 compareAndSetTail(Node expect,Node update),當(dāng)一個(gè)線程成功的獲取了同步狀態(tài)
(或者鎖)侥猬,其他線程將無(wú)法獲取到同步狀態(tài)例驹,轉(zhuǎn)而被構(gòu)造成為節(jié)點(diǎn)并加入到同步隊(duì)列中,而這個(gè)加入隊(duì)列的過(guò)程
必須要保證線程安全退唠。所以采用了基于CAS的方式來(lái)設(shè)置尾節(jié)點(diǎn)的方法鹃锈。
,需要傳遞當(dāng)前節(jié)點(diǎn)認(rèn)為的尾節(jié)點(diǎn)和當(dāng)前節(jié)點(diǎn)瞧预,只有設(shè)置成功后屎债,當(dāng)前節(jié)點(diǎn)才正式與之前的尾節(jié)點(diǎn)建立關(guān)聯(lián)。

3.3 成功獲取同步狀態(tài)

同步隊(duì)列遵循FIFO垢油,首節(jié)點(diǎn)是獲取同步狀態(tài)成功的節(jié)點(diǎn)盆驹,首節(jié)點(diǎn)的線程在釋放
同步狀態(tài)時(shí),會(huì)喚醒后繼節(jié)點(diǎn)滩愁,而后繼節(jié)點(diǎn)將會(huì)在獲取同步狀態(tài)成功時(shí)躯喇,將自己設(shè)置為首節(jié)點(diǎn)。

3.4 獨(dú)占式同步狀態(tài)獲取與釋放

  • 前驅(qū)節(jié)點(diǎn)為頭節(jié)點(diǎn)且能夠獲取同步狀態(tài)的判斷條件和線程進(jìn)入同步隊(duì)列 來(lái)獲
    取同步狀態(tài)是自旋的過(guò)程硝枉。
  • 設(shè)置首節(jié)點(diǎn)是通過(guò)獲取同步狀態(tài)成功的線程來(lái)完成的acquireQueued(node,args)完成的

獨(dú)占式獲取同步狀態(tài)的流程圖

獨(dú)占式同步狀態(tài)(鎖)獲取流程

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末廉丽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妻味,更是在濱河造成了極大的恐慌正压,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件责球,死亡現(xiàn)場(chǎng)離奇詭異焦履,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)棕诵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門裁良,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人校套,你說(shuō)我怎么就攤上這事价脾。” “怎么了笛匙?”我有些...
    開(kāi)封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵侨把,是天一觀的道長(zhǎng)犀变。 經(jīng)常有香客問(wèn)我,道長(zhǎng)秋柄,這世上最難降的妖魔是什么获枝? 我笑而不...
    開(kāi)封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮骇笔,結(jié)果婚禮上省店,老公的妹妹穿的比我還像新娘。我一直安慰自己笨触,他們只是感情好懦傍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著芦劣,像睡著了一般粗俱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上虚吟,一...
    開(kāi)封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天寸认,我揣著相機(jī)與錄音,去河邊找鬼串慰。 笑死偏塞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的邦鲫。 我是一名探鬼主播烛愧,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼掂碱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起慎冤,我...
    開(kāi)封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤疼燥,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蚁堤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體醉者,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年披诗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撬即。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呈队,死狀恐怖剥槐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宪摧,我是刑警寧澤粒竖,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布颅崩,位于F島的核電站,受9級(jí)特大地震影響蕊苗,放射性物質(zhì)發(fā)生泄漏沿后。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一朽砰、第九天 我趴在偏房一處隱蔽的房頂上張望尖滚。 院中可真熱鬧,春花似錦瞧柔、人聲如沸漆弄。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)置逻。三九已至,卻和暖如春备绽,著一層夾襖步出監(jiān)牢的瞬間券坞,已是汗流浹背万牺。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工拾枣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留椭盏,地道東北人粟誓。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓击奶,卻偏偏與公主長(zhǎng)得像堕澄,于是被迫代替她去往敵國(guó)和親秩贰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子螟深,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容