1-ReentrantLock
ReentrantLock是獨占鎖,而且內部可以是公平鎖,非公平鎖;
公平鎖:
公平鎖:加鎖錢需要檢查是否還有在排隊(等待)的線程,優(yōu)先排隊的
final void lock() {
acquire(1);
}
非公平鎖:
加鎖時無需考慮之前是否有線程等待,直接嘗試獲取鎖,獲取失敗會自動追加到同步隊列隊尾
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
2 上鎖流程
2.1 acquire方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected boolean tryAcquire(int var1) {
throw new UnsupportedOperationException();
}
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
涉及簡單方法分析:
- tryAcquire方法直接拋出異常,也即是自定義獨占鎖必須實現(xiàn)這個方法;
- selfInterrupt 獲取鎖的線程進行中斷操作,這個并不一定導致線程停止
2.2 addWaiter方法
整體來說,就是加入一個節(jié)點到隊列尾部;如果未初始化隊列,則進行初始化(延時策略)
private Node addWaiter(Node mode) {
Node node = new Node(mode);
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
U.putObject(node, Node.PREV, oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return node;
}
} else {
initializeSyncQueue();
}
}
}
- 首先生成一個Node節(jié)點,這個節(jié)點nextWaiter為空(Node.EXCLUSIVE為空對象);獨占鎖的nextWaiter為空
- for循環(huán)自旋
- 如果隊列未進行初始化,則initializeSyncQueue進行初始化,如果不成功,繼續(xù)此步驟直至成功
- 加入隊列尾部
2.3 acquireQueued方法
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
- for循環(huán)自旋;如果其是頭節(jié)點下的第一個節(jié)點,如果嘗試獲取資源成功,則進行設置為隊列頭,釋放之前頭節(jié)點,并返回false;返回false,則意味線程跳出自旋,可以繼續(xù)執(zhí)行
- 如果不是鎖等待隊列的第二個,則執(zhí)行shouldParkAfterFailedAcquire方法,如果為true,繼續(xù)執(zhí)行parkAndCheckInterrupt方法
- shouldParkAfterFailedAcquire方法執(zhí)行后,返回false會去掉取消的節(jié)點,之后如果未有狀態(tài)變化(比如外部取消線程,打斷等操作),則會返回true,可以詳細看下面方法源碼
2.4 shouldParkAfterFailedAcquire方法
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
}
return false;
}
- 如果node 前一個節(jié)點pred節(jié)點已經是等待喚醒狀態(tài),則返回true,表示當線線程應該被暫停
- 如果node前一個節(jié)點狀態(tài)大于0,暫時好像只有取消狀態(tài)的,則找到一個狀態(tài)小于等于0的,并是node為其后繼節(jié)點,則尋找過程中的節(jié)點都會被移除隊列,返回false
- 如果node前一個節(jié)點已經是小于等于0了,這時把前一個幾點的狀態(tài)置為等待喚醒-1,返回false
2.6 parkAndCheckInterrupt方法
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
- 暫停正在執(zhí)行的線程,并返回打斷狀態(tài)
3 釋放鎖流程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
- tryRelease需要自定義實現(xiàn),否則直接拋出異常
- 如果頭節(jié)點不是正在運行狀態(tài),則解鎖頭節(jié)點線程,釋放鎖成功
- 否則不需要釋放鎖,或者釋放失?。ò凑照?,在鎖等待隊列中,獨占鎖/條件鎖,都會為signal狀態(tài),為共享鎖為signal或者PROPAGATE狀態(tài))
3.1 unparkSuccessor方法
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
node.compareAndSetWaitStatus(ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node p = tail; p != node && p != null; p = p.prev)
if (p.waitStatus <= 0)
s = p;
}
if (s != null)
LockSupport.unpark(s.thread);
}
- CAS操作,釋放頭節(jié)點狀態(tài)設置為0
- 從頭結點后尋找一個節(jié)點不為空,且節(jié)點為0的節(jié)點,釋放此節(jié)點的線程(上述獲取資源時,進行自旋,去除頭結點后的取消的節(jié)點后的第一個節(jié)點才可以獲取資源)
4 獨占鎖原理小結
- nextWaiter為空
- 排隊等鎖的隊列,頭優(yōu)先獲取資源(對于非公平鎖,新獲取未排隊的線程也會獲取鎖);嘗試獲取資源的線程排隊到隊尾
- 獲取資源失敗的線程,被掛起;持有線程執(zhí)行完畢,則頭節(jié)點的下一個節(jié)點恢復執(zhí)行,嘗試獲取資源(非公平鎖,會和新獲取鎖未排隊進來的線程爭奪鎖)成功后繼續(xù)執(zhí)行其任務,失敗線程掛起,并置為等待喚醒狀態(tài)
- 可重入鎖,即當前線程再次獲取資源,狀態(tài)+1,釋放資源狀態(tài)-1,如果是0,則是當前線程完全釋放了資源,其它排隊線程可以獲取資源了;代碼如下:非公平鎖的代碼
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;
}
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;
}