下面來看ReentrantLock.unlock,嘗試在當前鎖的鎖定計數即state值上減1,而lock每次把鎖定計數加1,這也是爲什麼lock和unlock必須成對出現,否則鎖定計數就不能正常恢復到0,其它線程就不能嘗試獲取鎖
/**
* Attempts to release this lock.
*
* <p>If the current thread is the holder of this lock then the hold
* count is decremented. If the hold count is now zero then the lock
* is released. If the current thread is not the holder of this
* lock then {@link IllegalMonitorStateException} is thrown.
*
* @throws IllegalMonitorStateException if the current thread does not
* hold this lock
*/
public void unlock() {
sync.release(1);
}
* Attempts to release this lock.
*
* <p>If the current thread is the holder of this lock then the hold
* count is decremented. If the hold count is now zero then the lock
* is released. If the current thread is not the holder of this
* lock then {@link IllegalMonitorStateException} is thrown.
*
* @throws IllegalMonitorStateException if the current thread does not
* hold this lock
*/
public void unlock() {
sync.release(1);
}
AbstractQueuedsynchronizer.release(int arg)方法會在鎖定數目上減去arg,若新鎖定數目爲0,表示鎖被當前線程釋放, 則試圖喚醒等待隊列中的下一個線程。請注意這裏僅是喚醒,而非把鎖的所有權交給下一個線程。該線程能否成功獲取鎖,還要看運氣。
/**
* Releases in exclusive mode. Implemented by unblocking one or
* more threads if {@link #tryRelease} returns true.
* This method can be used to implement method {@link Lock#unlock}.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryRelease} but is otherwise uninterpreted and
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
/*head的waitStatus不爲零表示它的後繼在等待喚醒,
還記得AbstractQueuedSynchronizer.shouldParkAfterFailedAcquire中對waitStatus的操作麼?waitStatus!=0表明或者處於CANCEL狀態,或者是置SIGNAL表示下一個線程在等待其喚醒,CANCEL狀態這裏先不分析,可以認爲這裏!=0即表示SIGNAL狀態*/
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
* Releases in exclusive mode. Implemented by unblocking one or
* more threads if {@link #tryRelease} returns true.
* This method can be used to implement method {@link Lock#unlock}.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryRelease} but is otherwise uninterpreted and
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
/*head的waitStatus不爲零表示它的後繼在等待喚醒,
還記得AbstractQueuedSynchronizer.shouldParkAfterFailedAcquire中對waitStatus的操作麼?waitStatus!=0表明或者處於CANCEL狀態,或者是置SIGNAL表示下一個線程在等待其喚醒,CANCEL狀態這裏先不分析,可以認爲這裏!=0即表示SIGNAL狀態*/
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease定義在Sync類中
Sync.tryRelease會在當前鎖定狀態上減去要釋放的鎖定數,如果鎖定狀態爲零則置當前持有鎖線程爲null,返回true,否則返回false
此外還會檢查是否是佔有鎖的線程在調用,若不是則拋出IllegalMonitorStateException。
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;
}
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;
}
再來看unparkSuccessor
/**
* Wakes up node's successor, if one exists.
*
* @param node the node
*/
private void unparkSuccessor(Node node) {
/*
* Try to clear status in anticipation of signalling. It is
* OK if this fails or if status is changed by waiting thread.
*/
//若當前節點waitStatus被置爲SIGNAL則清零
compareAndSetWaitStatus(node, Node.SIGNAL, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
// 若後續節點爲空或已被cancel,則從尾部開始找到隊列中第一個waitStatus<=0,即未被cancel的節點
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
* Wakes up node's successor, if one exists.
*
* @param node the node
*/
private void unparkSuccessor(Node node) {
/*
* Try to clear status in anticipation of signalling. It is
* OK if this fails or if status is changed by waiting thread.
*/
//若當前節點waitStatus被置爲SIGNAL則清零
compareAndSetWaitStatus(node, Node.SIGNAL, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
// 若後續節點爲空或已被cancel,則從尾部開始找到隊列中第一個waitStatus<=0,即未被cancel的節點
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
再回頭看AbstractQueuedSynchronizer.acquireQueued,註釋1,2,3,4表明了在線程被喚醒後的執行順序
/**
* Acquires in exclusive uninterruptible mode for thread already in
* queue. Used by condition wait methods as well as acquire.
*
* @param node the node
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
//2 因爲等待隊列只會從尾部插入,所以在被喚醒節點和頭節點之間不會新加入等待節點,只會有節點被cancel
//3 如果被喚醒節點不是頭節點的直接後續,由喚醒算法可以保證其和頭結點之間沒有waitStatus<=0的節點,但有可能有waitStatus大於0,即被CANCEL的節點,參見注釋4
// 5獲取鎖成功則把當前節點設置爲頭節點,返回,否則線程繼續被禁止,直到下一次被喚醒
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
// 1 被lock.release喚醒,parkAndCheckInterrupt返回false,繼續回到for循環開始
//4 被cancel的結點在shouldParkAfterFailedAcquire中會被清理掉,當前節點會成爲頭節點的直接後繼,然後return false,在下次循環中即可嘗試獲取鎖
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
}
* Acquires in exclusive uninterruptible mode for thread already in
* queue. Used by condition wait methods as well as acquire.
*
* @param node the node
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
//2 因爲等待隊列只會從尾部插入,所以在被喚醒節點和頭節點之間不會新加入等待節點,只會有節點被cancel
//3 如果被喚醒節點不是頭節點的直接後續,由喚醒算法可以保證其和頭結點之間沒有waitStatus<=0的節點,但有可能有waitStatus大於0,即被CANCEL的節點,參見注釋4
// 5獲取鎖成功則把當前節點設置爲頭節點,返回,否則線程繼續被禁止,直到下一次被喚醒
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
// 1 被lock.release喚醒,parkAndCheckInterrupt返回false,繼續回到for循環開始
//4 被cancel的結點在shouldParkAfterFailedAcquire中會被清理掉,當前節點會成爲頭節點的直接後繼,然後return false,在下次循環中即可嘗試獲取鎖
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
}