引言
鎖,是java se 5之后提出的,它同synchronized關(guān)鍵字一樣,都是用來(lái)控制多個(gè)線程對(duì)臨界區(qū)訪問(wèn)的。
Lock與synchronized之間的區(qū)別和聯(lián)系
在總結(jié)兩者的區(qū)別和聯(lián)系之前先引入兩個(gè)概念:隱式鎖和顯式鎖。
- 隱式鎖:隱式獲取鎖,synchronized是它的代表,使用者不需要關(guān)心其內(nèi)部鎖的獲取和釋放,所有的鎖的相關(guān)操作都由具體的關(guān)鍵字完成;
- 顯式鎖:顯示地獲取鎖,Lock是它的代表,需要使用者在使用的時(shí)候顯示地獲取和釋放鎖。
顯式鎖和隱式鎖都實(shí)現(xiàn)了對(duì)臨界區(qū)訪問(wèn)的控制,但是顯式鎖提供了更靈活、更強(qiáng)大的接口:
- 隱式鎖將鎖的獲取和釋放固化了,只能先獲取再釋放;顯式鎖顯然無(wú)此約束,可以按照自己的需要來(lái)做鎖的釋放;
- 顯式鎖提供了可中斷獲取鎖以及超時(shí)獲取鎖等多種隱式鎖不具備的同步特性;
- 提供維度更小的等待與喚醒(Condition)。
就Lock接口提供的synchronized關(guān)鍵字不具備的特性做一個(gè)分析描述:
特性 | 描述 |
---|---|
嘗試非阻塞獲取鎖 | 當(dāng)前線程嘗試獲取鎖,如果鎖未被其他線程獲取,當(dāng)前線程成功獲取并持有鎖 |
可中斷獲取鎖 | 獲取鎖的線程能夠響應(yīng)中斷,當(dāng)獲取到鎖的線程被中斷時(shí),拋出中斷異常,鎖被釋放 |
超時(shí)獲取鎖 | 在指定的時(shí)間內(nèi)獲取鎖,如果在指定的時(shí)間內(nèi)未獲取到,獲取鎖失敗,返回 |
Lock的使用
案例1:
以讀寫鎖為例,Lock的使用方式很簡(jiǎn)單,只需要在需要加鎖的地方先獲取鎖,操作完成之后釋放鎖,需要注意的是:
- 要在finally中釋放鎖,這樣做的目的是保證在獲取到鎖之后,最終都是能夠被釋放;
- 不要將獲取鎖的過(guò)程寫在try代碼塊中,防止在獲取鎖發(fā)生異常時(shí)導(dǎo)致的鎖無(wú)故釋放。
Lock api
Lock是一個(gè)接口,定義了鎖的獲取和釋放等基本操作。
void lock()
線程調(diào)用該方法獲取鎖,獲取鎖后返回;void lockInterruptibly() throws InterruptedException
可中斷地獲取鎖,和lock()方法的區(qū)別在于該方法可以響應(yīng)中斷;boolean tryLock()
嘗試非阻塞獲取鎖,線程調(diào)用該方法后立刻返回,成功獲取到鎖返回true,否則返回false;-
boolean tryLock(long time, TimeUnit unit) throws InterruptedException
超時(shí)獲取鎖,該方法在以下3中情況會(huì)返回:- 在超時(shí)時(shí)間內(nèi)獲得鎖;
- 在超時(shí)時(shí)間被中斷;
- 超時(shí)時(shí)間結(jié)束仍未獲得,返回false。
void unlock()
釋放鎖;Condition newCondition()
獲取等待通知Condition組件,該組件和當(dāng)前鎖綁定,只有線程獲取到了鎖才能調(diào)用await()方法,調(diào)用后,當(dāng)前線程釋放鎖。
jdk中Lock接口的實(shí)現(xiàn)主要包括可重入鎖和讀寫鎖,它們也都是通過(guò)AQS來(lái)完成線程的訪問(wèn)控制的。