ReentrantLock和synchronized在jdk1.8版本後性能相差無幾,甚至synchronized小優,但是synchronized不支持中斷和超時,也就是說通過synchronized一旦被阻塞住,如果一直無法獲取到所資源就會一直被阻塞,即使中斷也沒用,這對併發系統的性能影響太大了;Lock支持中斷和超時、還支持嘗試機制獲取鎖,對synchronized進行了很好的擴展,所以從靈活性上Lock是明顯優於synchronized的
基本方法
// 構造方法
// boolean fair 是否爲公平鎖
ReentrantLock(boolean fair)
// 嘗試拿鎖,拿不到阻塞等待
void lock();
// 釋放鎖
void unlock();
// 等待拿鎖的時間可被中斷
void lockInterruptibly() throws InterruptedException;
// 嘗試拿鎖,不等待
boolean tryLock();
// 嘗試拿鎖,等待timeout時間
boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException;
公平鎖
拿鎖
final void lock() {
acquire(1);
}
public final void acquire(int arg) {
// 首先嚐試拿鎖
if (!tryAcquire(arg) &&
// addWaiter 拿鎖失敗時候 加入(創建)請求隊列
// acquireQueued 在一個死循環中 判斷是否是隊列頭 並嘗試拿鎖,否則阻塞 LockSupport.park(this)
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//嘗試拿鎖
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 當前鎖狀態爲空閒
// hasQueuedPredecessors 當前線程是否需要排隊(公平鎖) true: 需要, false: 不需要
if (!hasQueuedPredecessors() &&
// 通過 CAS 拿鎖
compareAndSetState(0, acquires)) {
// 成功拿到鎖之後設置當前持有鎖的線程爲當前線程
setExclusiveOwnerThread(current);
return true;
}
}
// 當前有線程持有鎖
// 判斷當前持有鎖的線程是否是當前線程
else if (current == getExclusiveOwnerThread()) {
// 是當前線程 則 c + 1 (可重入)
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc); // 設置當前鎖狀態
return true;
}
return false;
}
// 將當前線程加入請求隊列
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
// 判斷當前請求隊列是否存在
if (pred != null) {
// 隊列存在 則直接加入隊尾
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 隊列不存在 創建隊列 並 將當前請求放入隊列
enq(node);
return node;
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
// 死循環
for (;;) {
// 拿到當前線程的prev
final Node p = node.predecessor();
// 若 prev 是頭部 則嘗試拿鎖
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 判斷當前線程請求狀態是否應該 park
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) // 阻塞 LockSupport.park(this);
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
釋放鎖
public final boolean release(int arg) {
// 釋放鎖
if (tryRelease(arg)) {
Node h = head;
// 釋放成功後 將請求隊列的 head 節點 unpark 喚醒
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
// 鎖定次數 - 1
int c = getState() - releases;
// 判斷當前線程是否是當前持有鎖的線程
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 如果 c == 0 則 當前鎖爲空閒狀態
if (c == 0) {
free = true;
// 設置持有鎖的線程爲空
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
非公平鎖
final void lock() {
// 嘗試拿鎖 (插隊)
if (compareAndSetState(0, 1))
// 拿鎖成功 設置當前持有鎖的線程爲當前線程
setExclusiveOwnerThread(Thread.currentThread());
else
// 此方法與公平鎖使用同一個方法
acquire(1);
}
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) {
// 此處沒有判斷請求隊列 直接拿鎖 (插隊)
// 就沒有很嚴格的先後順序,
// 但是和公平鎖一樣是存在請求隊列
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;
}