在java中淹禾,協(xié)調(diào)對(duì)共享對(duì)象的訪問(wèn)時(shí)可以使用的機(jī)制包括synchronized,volatile以及java5.0之后新增的ReentrantLock機(jī)制。需要注意的是筷狼,ReentrantLock不是替代內(nèi)置鎖的方法,而是當(dāng)內(nèi)置鎖不適用時(shí)作為可選擇的高級(jí)功能裕偿。
Lock提供了一種無(wú)條件的,可輪詢的痛单,定時(shí)的以及可中斷的鎖獲取操作嘿棘。Lock的實(shí)現(xiàn)中必須提供與內(nèi)部所相同的內(nèi)存可見(jiàn)性語(yǔ)義。ReentrantLock實(shí)現(xiàn)了Lock接口旭绒,其提供的互斥性和內(nèi)存可見(jiàn)性與synchronized相同鸟妙。
使用示例(引自java并發(fā)編程實(shí)戰(zhàn)):
Lock lock=new ReentrantLock();
lock.lock();
try{
//更新對(duì)象狀態(tài)
//捕獲異常,并在必要時(shí)恢復(fù)不變性條件
}finally{
lock.unlock()挥吵;
}
需要注意的是重父,unlock操作必須在finally中,否則相當(dāng)于啟動(dòng)了"定時(shí)炸彈"忽匈。
如何選擇
顯示鎖提供了額外的功能房午,包括定時(shí),可中斷脉幢,公平性以及非塊結(jié)構(gòu)加鎖歪沃,此外性能上高于內(nèi)置鎖。
內(nèi)置鎖相對(duì)易于調(diào)試嫌松,通過(guò)線程轉(zhuǎn)儲(chǔ)可以給出哪些調(diào)用棧獲得了哪些鎖沪曙,并能檢測(cè)和識(shí)別發(fā)生死鎖的線程。它也是JVM的內(nèi)置屬性萎羔,在未來(lái)優(yōu)化性能的空間更大液走。
接口代碼
public interface Lock {
/*請(qǐng)求鎖,實(shí)現(xiàn)時(shí)應(yīng)該考慮能夠檢測(cè)出錯(cuò)誤的使用贾陷,如避免死鎖或者拋出未經(jīng)檢查的異常 */
void lock();
/*支持在請(qǐng)求鎖的時(shí)候被中斷 */
void lockInterruptibly() throws InterruptedException;
/*如果請(qǐng)求鎖時(shí)鎖可用則立即獲取并返回true,否則立即返回false */
boolean tryLock();
/*如果請(qǐng)求鎖時(shí)鎖可用則立即獲取并返回true 缘眶,否則線程進(jìn)入不可調(diào)度狀態(tài)直到以下三種情況:
*線程獲取鎖
*其他線程中斷當(dāng)前線程
*超時(shí)
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
/*返回一個(gè)新的綁定到當(dāng)前l(fā)ock實(shí)例的Condition對(duì)象實(shí)例 */
Condition newCondition();
}
public interface Condition{
/**
*使當(dāng)前線程等待直到被喚醒或者被中斷。
*與該Condition關(guān)聯(lián)的鎖會(huì)被自動(dòng)釋放髓废,然后線程進(jìn)入休直到以下四種情況:
*1.其他線程調(diào)用Condition的signal方法且當(dāng)前線程被選為被喚醒線程巷懈;
*2.其他線程調(diào)用signalAll方法;
*3.其他線程中斷了當(dāng)前線程慌洪;
*4.假喚醒顶燕。
*
*當(dāng)前線程在方法返回之前必須重新請(qǐng)求鎖
*/
void await() throws InterruptedException;
/*相對(duì)上一個(gè)方法,該方法不響應(yīng)中斷冈爹,直到被喚醒*/
void awaitUninterruptibly();
/*等待直到被喚醒涌攻,中斷或者指定時(shí)間超時(shí)*/
long awaitNanos(long nanosTimeout) throws InterruptedException;
/*等同于awaitNanos(unit.toNanos(time)) > 0*/
boolean await(long time,TimeUnit unit) throws InterruptedException;
/*指定deadline*/
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
}
Condition
在接口中出現(xiàn)了Condition類(lèi),在此簡(jiǎn)單的介紹一下條件隊(duì)列:條件隊(duì)列能使一組線程通過(guò)某種方式等待特定的條件為真频伤,該隊(duì)列中的元素是一個(gè)個(gè)正在等待相關(guān)條件的線程恳谎。
在java中,每個(gè)對(duì)象都可以作為一個(gè)條件隊(duì)列憋肖,可以在Object對(duì)象中看到因痛,每個(gè)對(duì)象都擁有wait(),notify()以及notifyAll()方法婚苹。而內(nèi)部鎖機(jī)制與內(nèi)部條件隊(duì)列是相互關(guān)聯(lián)的,要調(diào)用某對(duì)象條件隊(duì)列的方法時(shí)婚肆,必須持有該對(duì)象上的鎖租副。只有能對(duì)狀態(tài)進(jìn)行檢查時(shí)坐慰,才能在某個(gè)條件上等待较性,并且只有能修改狀態(tài)時(shí),才能從條件等待中釋放一個(gè)線程结胀。