ReentrantLock
是獨佔鎖,每次只能有一個執行緒能獲取到鎖(支援重入)。其他未獲取鎖的執行緒會放入的CLH佇列中,等待當前執行緒喚醒;
主要分為公平鎖和非公平鎖,由內部類FairSync
和 NoFairSync
來實現。主要的區別在於非公平鎖每次都會嘗試競爭,競爭不到鎖才會放入到CLH佇列中
- NonfairSync類
NonfairSync類繼承了Sync類,表示採用非公平策略獲取鎖,其實現了Sync類中抽象的lock方法,原始碼如下:
// 非公平鎖
static final class NonfairSync extends Sync {
// 版本號
private static final long serialVersionUID = 7316153563782823691L;
// 獲得鎖
final void lock() {
if (compareAndSetState(0, 1)) // 比較並設定狀態成功,狀態0表示鎖沒有被佔用
// 把當前執行緒設定獨佔了鎖
setExclusiveOwnerThread(Thread.currentThread());
else // 鎖已經被佔用,或者set失敗
// 以獨佔模式獲取物件,忽略中斷
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
說明: 從lock方法的原始碼可知,每一次都嘗試獲取鎖,而並不會按照公平等待的原則進行等待,讓等待時間最久的執行緒獲得鎖。
- FairSync類
FairSync類也繼承了Sync類,表示採用公平策略獲取鎖,其實現了Sync類中的抽象lock方法,原始碼如下:
// 公平鎖
static final class FairSync extends Sync {
// 版本序列化
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
// 以獨佔模式獲取物件,忽略中斷
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
// 嘗試公平獲取鎖
protected final boolean tryAcquire(int acquires) {
// 獲取當前執行緒
final Thread current = Thread.currentThread();
// 獲取狀態
int c = getState();
if (c == 0) { // 狀態為0
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) { // 不存在已經等待更久的執行緒並且比較並且設定狀態成功
// 設定當前執行緒獨佔
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 狀態不為0,即資源已經被執行緒佔據
// 下一個狀態
int nextc = c + acquires;
if (nextc < 0) // 超過了int的表示範圍
throw new Error("Maximum lock count exceeded");
// 設定狀態
setState(nextc);
return true;
}
return false;
}
}
說明: 跟蹤lock方法的原始碼可知
主要區別就在於hasQueuedPredecessors方法,先會判斷是否存在等待佇列。
示例:
private ReentrantLock lock = new ReentrantLock();
public void test(){
lock.lock();
try {
...
}finally {
lock.unlock();
}
}