Java并發(fā)編程之鎖機(jī)制之Lock接口

小盒子.jpg

該文章屬于《Java并發(fā)編程》系列文章缭贡,如果想了解更多窗价,請點(diǎn)擊《Java并發(fā)編程之總目錄》

前言

在上篇文章《Java并發(fā)編程之鎖機(jī)制之引導(dǎo)篇》中灿椅,我們大致了解了Lock接口(以及相關(guān)實(shí)現(xiàn)類)在并發(fā)編程重要作用殊者。接下來我們就來具體了解Lock接口中聲明的方法以及使用優(yōu)勢恨憎。

Lock簡介

Lock 接口實(shí)現(xiàn)類提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作蕊退。此實(shí)現(xiàn)允許更靈活的結(jié)構(gòu),可以具有差別很大的屬性憔恳,可以支持多個相關(guān)的 Condition (Condition實(shí)現(xiàn)類ConditonObject來實(shí)現(xiàn)線程的通知/與喚醒機(jī)制咕痛,關(guān)于Condition后期會進(jìn)行介紹)對象。

鎖是用于控制多線程訪問共享資源的工具喇嘱。通常茉贡,鎖提供對共享資源的獨(dú)占訪問:一次只有一個線程可以獲取鎖,對共享資源的所有訪問都需要首先獲取鎖者铜。但是腔丧,一些鎖可以允許同時(shí)訪問共享資源,例如ReadWriteLock作烟。

雖然使用關(guān)鍵字synchronized修飾的方法或代碼塊愉粤,會使得在監(jiān)視器模式(ObjectMonitor)下編程變得非常容易(通過synchronized塊或者方法所提供的隱式獲取釋放鎖的便捷性)。雖然這種方式簡化了鎖的管理拿撩,但是某些情況下衣厘,還是建議采用Lock接口(及其相關(guān)子類)提供的顯示的鎖的獲取和釋放。例如压恒,針對一個場景影暴,手把手進(jìn)行鎖獲取和釋放,先獲得鎖A探赫,然后再獲取鎖B型宙,當(dāng)鎖B獲得后,釋放鎖A同時(shí)獲取鎖C伦吠,當(dāng)鎖C獲得后妆兑,再釋放B同時(shí)獲取鎖D,以此類推毛仪。這種場景下搁嗓,
synchronized關(guān)鍵字就不那么容易實(shí)現(xiàn)了,而Lock接口的實(shí)現(xiàn)類允許鎖在不同的作用范圍內(nèi)獲取和釋放箱靴,并允許以任何順序獲取和釋放多個鎖腺逛。

Lock接口中的方法

關(guān)于Lock接口中涉及到的方法具體如下:(建議直接在PC端查看,手機(jī)上有可能看的不是很清楚)


lock_method.png

從上表中刨晴,我們就可以得出使用Lock接口實(shí)現(xiàn)的鎖機(jī)制與使用傳統(tǒng)的synchronized的區(qū)別

  1. 嘗試非阻塞地獲取鎖:當(dāng)線程嘗試獲取鎖屉来,如果這一時(shí)刻鎖沒有被其他線程獲取到路翻,則成功獲取并持有鎖。
  2. 能被中斷的獲取鎖:與synchronized不同茄靠,獲取到鎖的線程能夠響應(yīng)中斷茂契,當(dāng)獲取到鎖的線程被中斷時(shí),中斷異常會被拋出慨绳,同時(shí)鎖也會被釋放掉冶。
  3. 超時(shí)獲取鎖:在指定的截止時(shí)間之前獲取鎖,如果截止時(shí)間到了任然無法獲取到鎖脐雪,則返回厌小。

Lock簡單使用與注意事項(xiàng)

其中Lock的使用方式也很簡單,具體代碼如下所示:

Lock lock = ....;具體實(shí)現(xiàn)類
lock.lock();
try {
} finally {
lock.unlock();//建議在finally中釋放鎖
}

當(dāng)鎖定和解鎖發(fā)生在不同的范圍時(shí)战秋,一定要注意確保在持有鎖時(shí)執(zhí)行的所有代碼都受到try-finally或try-catch的保護(hù)璧亚,以確保在必要時(shí)釋放鎖。不要將獲取鎖的過程寫在try塊中脂信,因?yàn)槿绻讷@取鎖(自定義鎖的實(shí)現(xiàn))時(shí)發(fā)生了異常癣蟋,異常拋出的同時(shí),也會導(dǎo)致鎖無故釋放(因?yàn)橐坏┌l(fā)生異常狰闪,就會走finally語句疯搅,如果這個異常(可能是用戶自定義異常,用戶可以自己處理)需要線程1來處理埋泵,但是接著執(zhí)行了lock.unlock()語句導(dǎo)致了鎖的釋放幔欧。那么其他線程就可以操作共享資源。有可能破壞程序的執(zhí)行結(jié)果)丽声。

Lock相關(guān)實(shí)現(xiàn)類實(shí)現(xiàn)鎖機(jī)制

為了使用Lock接口實(shí)現(xiàn)相關(guān)鎖功能時(shí)礁蔗,會涉及以下類和接口,這里還是把上篇文章提到的UML圖展示出來:

lock.png

上圖中恒序,

  1. 綠色部分為:其中ReentrantLock(重入鎖)瘦麸、WriteLock谁撼、ReadLock都是Lock的實(shí)現(xiàn)類歧胁。Segment為ReentrantLock的子類(在后續(xù)文章,ConcurrentHashMap的講解中我們會提及)厉碟。 ReentrantReadWriteLock (讀寫鎖)的實(shí)現(xiàn)使用了WriteLock與ReadLock類喊巍。
  2. 紫色部分為:其中AbstractQueuedSynchronizerAbstractQueuedLongSynchronizer都為AbstractOwnableSynchronizer的子類,該兩個類中都維護(hù)了一個同步隊(duì)列箍鼓,用于線程的并發(fā)執(zhí)行崭参。在該兩個類中擁有名為ConditionObject(為Conditon的實(shí)現(xiàn)類)的內(nèi)部類,只是其內(nèi)部實(shí)現(xiàn)不同款咖。在ConditionObject內(nèi)部維護(hù)了一個等待隊(duì)列何暮,用于控制線程的等待與喚醒奄喂。

基本代碼結(jié)構(gòu)

在了解了Lock相關(guān)實(shí)現(xiàn)類實(shí)現(xiàn)鎖機(jī)制后,這里給實(shí)現(xiàn)該鎖機(jī)制的大致代碼結(jié)構(gòu)(根據(jù)不同需求海洼,部分方法實(shí)現(xiàn)可能不一樣跨新,這里只是一個參考,并不是樣本代碼)坏逢。具體代碼如下所示:

class LockImpl implements Lock {

    private final sync mSync = new sync();
    @Override
    public void lock() {
        mSync.acquire(1);
    }
    @Override
    public void lockInterruptibly() throws InterruptedException {
        mSync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return mSync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return mSync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        mSync.release(1);
    }

    @Override
    public Condition newCondition() {
        return mSync.newCondition();
    }
    
     //這里也可以繼承AbstractQueuedLongSynchronizer
    private static class sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean isHeldExclusively() {...}
        @Override
        protected boolean tryAcquire(int arg) {...}
        @Override
        protected boolean tryRelease(int arg) {...}
        @Override
        protected int tryAcquireShared(int arg) {...}
        @Override
        protected boolean tryReleaseShared(int arg) {...}
        final ConditionObject newCondition() {...}
    }
}

從代碼中我們可以看出域帐,在整個Lock接口下實(shí)現(xiàn)的鎖機(jī)制中,AQS(這里我們將AbstractQueuedSynchronizer 或AbstractQueuedLongSynchronizer統(tǒng)稱為AQS)是實(shí)現(xiàn)鎖的關(guān)鍵是整,整個鎖的實(shí)現(xiàn)是在Lock類的實(shí)現(xiàn)類中聚合AQS來實(shí)現(xiàn)的肖揣,從代碼層面上來說,Lock接口(及其實(shí)現(xiàn)類)是面向使用者的浮入,它定義了使用者與鎖交互的接口(比如可以允許兩個線程并行訪問)龙优,隱藏了實(shí)現(xiàn)細(xì)節(jié)。AQS與Condition才是真正的實(shí)現(xiàn)者事秀,它簡化了鎖的實(shí)現(xiàn)方式陋率,屏蔽了同步狀態(tài)管理、線程的排隊(duì)秽晚、等待與喚醒等底層操作瓦糟。

總結(jié)

  1. Lock接口(及其實(shí)現(xiàn)類)相比synchronized有如下優(yōu)點(diǎn):
  • 鎖的釋放與獲取不在是隱式的,允許鎖在不同的作用范圍內(nèi)獲取和釋放`赴蝇,并允許以任何順序獲取和釋放多個鎖菩浙。
  • 能被中斷的獲取鎖,獲取到鎖的線程能夠響應(yīng)中斷句伶,當(dāng)獲取到鎖的線程被中斷時(shí)劲蜻,中斷異常會被拋出,同時(shí)鎖也會被釋放
  • 超時(shí)獲取鎖:在指定的截止時(shí)間之前獲取鎖考余,如果截止時(shí)間到了任然無法獲取到鎖先嬉,則返回。
  1. 在使用Lock的時(shí)候注意楚堤,一定要確保必要時(shí)釋放鎖
  2. 在整個Lock接口下實(shí)現(xiàn)的鎖機(jī)制中,AQS(上文進(jìn)行了統(tǒng)稱)與Condition才是真正的實(shí)現(xiàn)者疫蔓。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市身冬,隨后出現(xiàn)的幾起案子衅胀,更是在濱河造成了極大的恐慌,老刑警劉巖酥筝,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滚躯,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)掸掏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門茁影,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人丧凤,你說我怎么就攤上這事呼胚。” “怎么了息裸?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵蝇更,是天一觀的道長。 經(jīng)常有香客問我呼盆,道長年扩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任访圃,我火速辦了婚禮厨幻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腿时。我一直安慰自己况脆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布批糟。 她就那樣靜靜地躺著格了,像睡著了一般。 火紅的嫁衣襯著肌膚如雪徽鼎。 梳的紋絲不亂的頭發(fā)上盛末,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機(jī)與錄音否淤,去河邊找鬼悄但。 笑死,一個胖子當(dāng)著我的面吹牛石抡,可吹牛的內(nèi)容都是我干的檐嚣。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼啰扛,長吁一口氣:“原來是場噩夢啊……” “哼嚎京!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侠讯,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤挖藏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后厢漩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岩臣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年溜嗜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宵膨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡炸宵,死狀恐怖辟躏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情土全,我是刑警寧澤捎琐,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站裹匙,受9級特大地震影響瑞凑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜概页,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一籽御、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惰匙,春花似錦技掏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至绘盟,卻和暖如春涧衙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奥此。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工弧哎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稚虎。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓撤嫩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蠢终。 傳聞我的和親對象是個殘疾皇子序攘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

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