鎖的可重入性是為了防止已經(jīng)獲得鎖的線程再次獲得鎖可能會(huì)帶來(lái)的死鎖問(wèn)題衡瓶,比如:
public synchronized void A(){
B();
}
public synchronized void B(){
}
如果Java內(nèi)置的synchronized
鎖不是可重入的驾胆,則線程A在獲得鎖進(jìn)入A()
后調(diào)用B()
時(shí),需要等待線程A釋放鎖端辱,而此時(shí)線程A還沒(méi)有完成A()
得哆,則不會(huì)釋放鎖脯颜,因此產(chǎn)生死鎖。
一個(gè)簡(jiǎn)單的可重入鎖實(shí)現(xiàn)
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 簡(jiǎn)單的可重入鎖實(shí)現(xiàn):
* 使用一個(gè)計(jì)數(shù)器記錄當(dāng)前線程重入鎖的次數(shù)贩据,獲得鎖時(shí)計(jì)數(shù)器加1栋操,
* 釋放鎖時(shí)計(jì)數(shù)器減1,當(dāng)計(jì)數(shù)器等于0時(shí)表示釋放了鎖
**/
public class SimpleReentrantLock implements Lock{
// 指向已經(jīng)獲得鎖的線程
private volatile Thread exclusiveOwnerThread;
// 記錄獲取了同一個(gè)鎖的次數(shù)
private volatile int holdCount;
private final java.util.concurrent.locks.Lock lock;
// 是否是自己獲得鎖的條件
private final Condition isCountZero;
public SimpleReentrantLock(){
lock = new ReentrantLock();
isCountZero = lock.newCondition();
holdCount = 0;
}
@Override
public void lock() {
lock.lock();
try{
// 當(dāng)前線程的引用
Thread currentThread = Thread.currentThread();
// 如果獲得鎖的線程是自己饱亮,那么計(jì)數(shù)器加1矾芙,直接返回
if(exclusiveOwnerThread == currentThread){
holdCount ++;
return;
}
while(holdCount != 0){
try {
isCountZero.await();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted");
}
}
// 將exclusiveOwnerThread設(shè)置為自己
exclusiveOwnerThread = currentThread;
holdCount ++;
}finally{
lock.unlock();
}
}
@Override
public void unlock() {
lock.lock();
try{
holdCount --;
if(holdCount == 0){
isCountZero.signalAll();
}
}finally{
lock.unlock();
}
}
}
- 使用一個(gè)Thread引用指向獲得鎖的線程
- 使用一個(gè)計(jì)數(shù)器記錄一個(gè)線程進(jìn)入鎖的次數(shù),當(dāng)計(jì)數(shù)器為0時(shí)表示鎖是空閑的
- 使用一個(gè)內(nèi)部鎖Lock來(lái)同步線程
- 使用一個(gè)isHoldZero的條件來(lái)進(jìn)行條件隊(duì)列操作
- 當(dāng)獲得鎖的線程是自己時(shí)近上,只修改計(jì)數(shù)器的值蠕啄,直接獲得鎖
- 當(dāng)獲得鎖的線程不是自己時(shí),需要在holdCount !=0 這個(gè)條件謂詞上等待,直到計(jì)數(shù)器歸0歼跟,再次競(jìng)爭(zhēng)鎖
- 釋放鎖時(shí)計(jì)數(shù)器減1和媳,當(dāng)計(jì)數(shù)器為0時(shí),喚醒在條件隊(duì)列中等待的線程
問(wèn)題1:為什么鎖要具備可重入性哈街?