5.1 LOCK接口
鎖是用于控制多個線程訪問共享資源的方式。一般來說,一個鎖能夠防止多個線程同一時間訪問一個共享資源(但是有些鎖可以允許多個線程并發(fā)的訪問共享資源,比如讀寫鎖)。
Lock接口提供了與synchronized關(guān)鍵字類似的功能,只是在使用時需要顯示的獲取和釋放鎖。雖然它缺少了(synchronized塊或方法所提供的)隱式獲取和釋放鎖的便捷性,但是卻擁有了鎖獲取與釋放的可操作性,可中斷的獲取鎖以及超時獲取鎖等synchronized關(guān)鍵字所不具備的同步特性。
Lock接口的使用示例:
Lock lock = new ReentrantLock();
lock.lock();
try{
}finally{
? ? ? lock.unlock();
}
Lock 接口所提供的的synchronized關(guān)鍵字不具備的功能:
(1)嘗試非阻塞的獲取鎖。
(2)能被中斷地獲取鎖:與synchronized不同,當(dāng)獲取到鎖的線程被中斷時,中斷異常將被拋出,同時鎖被釋放。
(3)超時獲取鎖:如果在規(guī)定時間內(nèi)無法獲得鎖,則及時返回。
5.2 隊列同步器
隊列同步器AbstractQueuedSynchronizer,使用來構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架。
同步器主要通過操作3個方法來對同步狀態(tài)進(jìn)行更改,getState(),setState(int newState),compareAndSet(int expected,intupdate)。這些方法能都保證狀態(tài)的改變是安全的。
同步器是實現(xiàn)鎖(或任何其他同步組件)的關(guān)鍵,通常在鎖的實現(xiàn)中聚合同步器,利用同步器來實現(xiàn)鎖的語義。同步器簡化了鎖的實現(xiàn),屏蔽了同步狀態(tài)管理,線程的排隊,等待與喚醒等底層操作。
5.2.1 隊列同步器的接口與示例
(1)隊列同步器是基于模板方法模式的,也就是說,使用者需要繼承同步器并重寫指定的方法。
同步器可重寫的方法如下:
(1)protected boolean tryAcquire(int arg):獨(dú)占式的獲取同步狀態(tài),實現(xiàn)該方法需要判斷同步狀態(tài)是否符合預(yù)期,然后進(jìn)行CAS設(shè)置同步狀態(tài)。
(2)protected boolean tryRelease(int arg):獨(dú)占式釋放同步狀態(tài),等待獲取同步狀態(tài)的線程將有機(jī)會獲取同步狀態(tài)。
(3)protected boolean tryAcquireShared(int arg):共享式獲取同步狀態(tài),返回大于0的值,表示獲取成功,反之,獲取失敗。
(4)protected boolean tryReleaseShared(int arg):共享式釋放同步狀態(tài)
(5)protected boolean isHeldExclusively():是否被當(dāng)前線程獨(dú)占
同步器提供的模板方法:
(1)void acquire(int arg):獨(dú)占式獲取同步狀態(tài),如果當(dāng)前線程獲取同步狀態(tài)成功,則由該方法返回,否則,線程進(jìn)入同步隊列等待,該方法會調(diào)用重寫的tryAcquire方法。
(2)void acquireInterruptibly(int arg):與acquire(int arg)相同,但是該方法能夠響應(yīng)中斷,如果當(dāng)前線程被中斷,則該方法會拋出InterruptedException并返回。
(3)boolean tryAcquireNanos(int arg,long nanos):在acquireInterruptibly(int arg)的基礎(chǔ)上增加了超時限制,如果當(dāng)前線程在超時時間內(nèi)沒有獲取到同步狀態(tài),那么將返回false,否則返回true。
(4)boolean release(int arg):獨(dú)占式釋放同步狀態(tài),該方法會在釋放同步狀態(tài)之后,將同步狀態(tài)中第一個節(jié)點(diǎn)包含的線程喚醒。
(5)Collection<Thread> getQueuedThreads():獲取等待在同步隊列上的線程集合
同步器提供的方法主要分為3類:獨(dú)占式獲取和釋放同步狀態(tài),共享式獲取和釋放同步狀態(tài),查詢同步隊列中的等待線程情況。
5.3 重入鎖
重入鎖(ReentrantLock),就是支持重進(jìn)入的鎖,它表示該鎖能夠支持一個線程對資源的重復(fù)加鎖。除此之外,該鎖還支持獲取鎖時的公平和非公平性選擇。
synchronized關(guān)鍵字隱式的支持重進(jìn)入。
(1)公平鎖:如果在絕對時間上,先對鎖進(jìn)行請求的鎖先被滿足,那么這個鎖就是公平的,反之,就是不公平的。公平的獲取鎖,也就是等待時間最長的線程最優(yōu)先獲得鎖,也可以說鎖的獲取是順序的。
(2)事實上,公平鎖往往沒有非公平鎖的效率高(公平鎖造成大量的線程切換開銷),但是,公平鎖能夠減少“饑餓”發(fā)生的概率。
(3)非公平鎖雖然可能造成線程饑餓,但極少的線程切換,保證了其更大的吞吐量。
ReentrantLock的實現(xiàn):
(1)nonfairTryAcquire:判斷當(dāng)前線程是否為獲取鎖的線程,如果是,則將同步狀態(tài)的值增加并返回true。
(2)tryRelease:如果該鎖被獲取了n次,那么前(n-1)次tryRelease方法必須返回flase,而只有同步狀態(tài)最終被減為0的時候才能返回true。
(3)公平鎖的tryAcquire與nonfairTryAcquire唯一的區(qū)別就是,判斷條件多了hasQueuedPredecessors()方法,即加入了同步隊列當(dāng)前節(jié)點(diǎn)是否有前驅(qū)節(jié)點(diǎn)的判斷,如果有的話,tryAcquire會返回false。