節點狀態
/** 節點已被取消 */
static final int CANCELLED = 1;
/**
* 後繼節點的執行緒處於等待狀態,
* 而當前節點的執行緒如果釋放了同步狀態或者被取消,
* 那麼就會通知後繼節點,讓後繼節點的執行緒能夠執行
*/
static final int SIGNAL = -1;
/**
* 節點在等待佇列中,節點執行緒等待在Condition上,
* 不過當其他的執行緒對Condition呼叫了signal()方法後,
* 該節點就會從等待佇列轉移到同步佇列中,然後開始嘗試對同步狀態的獲取
*/
static final int CONDITION = -2;
/**
* 表示下一次的共享式同步狀態獲取將會無條件的被傳播下去
*/
static final int PROPAGATE = -3;
lock
方法流程
透過流程可以看出,公平與非公平只針對新執行緒與同步佇列中的執行緒。
原始碼:
- 公平鎖
final void lock() {
// 呼叫父類的 acquire
acquire(1);
}
// 父類
public final void acquire(int arg) {
// 嘗試搶鎖
if (!tryAcquire(arg) &&
// 搶鎖失敗加入佇列排隊獲取鎖,此步驟為自旋阻塞,addWaiter對應流程圖2
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 如果在佇列中搶鎖失敗,則關閉當前執行緒
selfInterrupt();
}
// 嘗試搶鎖
protected final boolean tryAcquire(int acquires) {
// 獲取當前執行緒
final Thread current = Thread.currentThread();
// 獲取當前 state 值
int c = getState();
// 如果當前 state 為沒人佔用狀態
if (c == 0) {
// 同步佇列中是否有搶鎖的執行緒,對應流程圖1
if (!hasQueuedPredecessors() &&
// 如果前面沒有搶鎖的執行緒,CAS 改寫 state
compareAndSetState(0, acquires)) {
// 如果寫成功則將當前鎖的持有人標記為當前執行緒
setExclusiveOwnerThread(current);
return true;
}
}
// 當前 state 為當前執行緒佔用
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
- 非公平鎖
final void lock() {
// CAS 改寫 state,寫成功代表搶鎖成功
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 上面寫失敗了就呼叫父級的 acquire 方法,同公平鎖
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;
}
- acquireQueued 佇列阻塞搶鎖
// 對應流程3
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 獲取當前結點的上一個節點
final Node p = node.predecessor();
// 如果上一個節點為 head,則嘗試獲取鎖
if (p == head && tryAcquire(arg)) {
// 搶鎖成功後將 head 設為當前節點
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 搶鎖失敗,判斷當前執行緒是否應該關閉
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
// 搶鎖失敗,進行取消操作
if (failed)
cancelAcquire(node);
}
}
wait & signal (等待與喚醒)
阻塞佇列中,如果當前佇列為空,則會呼叫
notEmpty.await()
方法,notEmpty
為ConditionObject
,通常阻塞佇列中會有兩個ConditionObject
,一個負責【取(notEmpty)】的執行緒,一個負責【存(notFull)】的執行緒。一個ConditionObject
就是一個等待佇列,呼叫await()
方法就是將當前執行緒從同步佇列移到等待佇列中。
原始碼解析:
public final void await() throws InterruptedException {
// 如果當前執行緒是中斷狀態則丟擲中斷異常
if (Thread.interrupted())
throw new InterruptedException();
// 將節點加入等待佇列,對應流程1
Node node = addConditionWaiter();
// 釋放當前節點所持的鎖,對應流程2
int savedState = fullyRelease(node);
int interruptMode = 0;
// 如果當前節點不在同步佇列中,則掛起等待喚醒,對應流程3
// 當執行緒被喚醒時,節點會加入同步佇列,則會跳出 while,進入下面的邏輯
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 進入同步佇列搶鎖
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
- signal
public final void signal() {
// 如果不是當前持鎖的執行緒操作,則丟擲異常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
// 如果等待佇列有執行緒在等待
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
/*
* 如果不能修改狀態,則表示當前節點已被取消
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 將節點加入同步佇列,返回當前節點的上一個節點
Node p = enq(node);
// 獲取上一個節點的等待狀態
int ws = p.waitStatus;
// 如果上一個節點為取消
// 或者上一個節點的狀態已經時 SIGNAL 狀態
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
// 喚醒當前節點
LockSupport.unpark(node.thread);
// 否則就交給同步佇列進行喚醒,每個執行緒釋放鎖時都會去喚醒他的下一個節點
return true;
}
- realse
public final boolean release(int arg) {
// 嘗試釋放鎖
if (tryRelease(arg)) {
Node h = head;
// 釋放成功後喚醒下一個節點(如果有的話),對應流程4
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結