ReentrantLock仰楚,可重入鎖,是一種遞歸無阻塞的同步機制敦姻。它可以等同于synchronized的使用宛徊,但是ReentrantLock提供了比synchronized更強大崔梗、靈活的鎖機制夜只,可以減少死鎖發(fā)生的概率。
A reentrant mutual exclusion Lock with the same basic behavior and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities.
A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it. A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. The method will return immediately if the current thread already owns the lock. This can be checked using methods isHeldByCurrentThread, and getHoldCount.
本文將結(jié)合 **JDK1.7 ** 源碼來分析java.util.concurrent.locks.ReentrantLock內(nèi)部實現(xiàn)原理蒜魄。
首先扔亥,看看ReentrantLock 的構(gòu)造方法:
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
private final Sync sync;
/**
* 默認構(gòu)造方法
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 帶fair參數(shù)的構(gòu)造方法
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
}
Sync為ReentrantLock里面的一個內(nèi)部類,它繼承AQS(AbstractQueuedSynchronizer)谈为,它有兩個子類:公平鎖FairSync和非公平鎖NonfairSync旅挤。
獲取鎖
ReentrantLock的lock方法如下:
public void lock() {
sync.lock();
}
下面我們看非公平鎖(NonfairSync)的lock()方法:
final void lock() {
if (compareAndSetState(0, 1)) //嘗試獲取鎖
setExclusiveOwnerThread(Thread.currentThread());
else //獲取鎖失敗
acquire(1);
}
首先會第一次嘗試快速獲取鎖,如果獲取失敗伞鲫,則調(diào)用acquire(int arg)方法粘茄,該方法定義在AQS中,如下:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
這個方法首先調(diào)用tryAcquire(int arg)方法秕脓,在AQS中講述過柒瓣,tryAcquire(int arg)需要自定義同步組件提供實現(xiàn),非公平鎖實現(xiàn)如下:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
//當前線程
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { //state == 0,表示沒有該鎖處于空閑狀態(tài)
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//判斷鎖持有的線程是否為當前線程
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
首先判斷同步狀態(tài)state 是否為0吠架,如果為0表示該鎖還沒有被線程持有芙贫,直接通過CAS獲取同步狀態(tài),CAS成功則返回true傍药。如果state不為0磺平,則判斷當前線程是否為獲取鎖的線程,如果是則獲取鎖拐辽,成功返回true拣挪。
釋放鎖
獲取同步鎖后,使用完畢則需要釋放鎖俱诸,ReentrantLock提供了unlock釋放鎖:
public void unlock() {
sync.release(1);
}
unlock方法內(nèi)部調(diào)用了Sync的release(int arg)釋放鎖菠劝,release(int arg)是在AQS中定義的:
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
與獲取同步狀態(tài)的acquire(int arg)方法相似,釋放同步狀態(tài)的tryRelease(int arg)同樣是調(diào)用Sync的tryRelease方法:
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
公平鎖與非公平鎖
公平鎖與非公平鎖的區(qū)別在于獲取鎖的時候是否按照FIFO的順序來乙埃。釋放鎖不存在公平性和非公平性闸英,上面以非公平鎖為例,下面我們來看看公平鎖(FairSync)的tryAcquire(int arg):
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
比較非公平鎖和公平鎖獲取同步狀態(tài)的過程介袜,會發(fā)現(xiàn)兩者唯一的區(qū)別就在于公平鎖在獲取同步狀態(tài)時多了一個限制條件:hasQueuedPredecessors()甫何,定義如下:
public final boolean hasQueuedPredecessors() {
Node t = tail; //尾節(jié)點
Node h = head; //頭節(jié)點
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
該方法主要做一件事情:主要是判斷當前線程是否位于CLH同步隊列中的第一個。如果是則返回true遇伞,否則返回false辙喂。
ReentrantLock與synchronized的區(qū)別
ReentrantLock在加鎖和內(nèi)存上提供的語義與內(nèi)置鎖相同,區(qū)別在于:
- ReentrantLock提供了一些其他功能,具備更強的擴展性巍耗,包括:定時的鎖等待秋麸,可中斷的鎖等候,公平性炬太。
- ReentrantLock提供了條件(Condition)灸蟆,對線程的等待、喚醒操作更加詳細和靈活亲族。