ReentranLock是我們常用的同步鎖派敷。它里面主要會用到的方法就是lock() unlock(),下面我們來看下它的源碼實(shí)現(xiàn)科贬。
首先它有兩種鎖的方式 公平鎖 和 非公平鎖呐矾。其中兩者的區(qū)別在于非公平鎖每個線程不管有沒有比它先的,都直接去嘗試獲取鎖雏赦,而公平鎖會先判斷存不存在有等待的線程恰响,有等待的線程直接加入到隊(duì)列趣钱。
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* 當(dāng)我們調(diào)用這個方法的第一步就是CAS state值涌献,這個方法保證在多個
線程的情況下只有一個線程會成功
如果設(shè)置成功 那就設(shè)置當(dāng)前線程設(shè)置成aqs的owner
如果設(shè)置失敗(表示當(dāng)前已經(jīng)有線程拿到了aqs的鎖) 調(diào)用acquire(1)方法
這個方法在aqs里面
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {//這里就是和公平鎖不一樣的地方 每進(jìn)來一個線程都會直接去嘗試獲取鎖 而公平鎖會直接放入隊(duì)列
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;
}
我們走到acquire(1)胚宦,就能看到當(dāng)沒獲取到鎖的時候,首先還是會去嘗試獲取鎖燕垃,因?yàn)榭赡茏铋_始的線程已經(jīng)執(zhí)行完了枢劝,這個時候還是通過compareAndSetState
去獲取鎖,并且此時是支持可重入的卜壕,也就是說如果當(dāng)前aqs Owner的線程進(jìn)來會把state的值+1您旁。
下一步當(dāng)?shù)诙潍@取鎖失敗之后,會調(diào)用acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
方法轴捎,我們先看addWaiter(Node.EXCLUSIVE)
的作用鹤盒。
private Node addWaiter(Node mode) {
//初始化一個當(dāng)前線程節(jié)點(diǎn)
Node node = new Node(Thread.currentThread(), mode);
// 找到隊(duì)尾節(jié)點(diǎn)
Node pred = tail;
if (pred != null) {
//當(dāng)隊(duì)尾節(jié)點(diǎn)存在 把當(dāng)前節(jié)點(diǎn)前置指針指向隊(duì)尾節(jié)點(diǎn)
node.prev = pred;
//把當(dāng)前節(jié)點(diǎn)設(shè)置成隊(duì)尾節(jié)點(diǎn) 這個地方也用cas操作 因?yàn)榭赡芡瑫r存在很多線程在插入隊(duì)尾 保證
只有一個線程插入成功
if (compareAndSetTail(pred, node)) {
//插入成功之后把之前的隊(duì)尾的后置節(jié)點(diǎn)指向它 返回出去
pred.next = node;
return node;
}
}
//如果當(dāng)前節(jié)點(diǎn)未成功放至隊(duì)尾 進(jìn)入該方法直到放至成功
enq(node);
return node;
}
private Node enq(final Node node) {
//自旋直至節(jié)點(diǎn)放置成功
for (;;) {
//獲取隊(duì)尾
Node t = tail;
if (t == null) { // 如果隊(duì)尾為空 初始化空節(jié)點(diǎn) 并且頭尾相連
if (compareAndSetHead(new Node()))
tail = head;
} else {
如果隊(duì)尾存在,把當(dāng)前節(jié)點(diǎn)放置進(jìn)去
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
所以我們可以知道``addWaiter(Node.EXCLUSIVE)方法的作用就是把當(dāng)前線程加入到aqs的隊(duì)列里面侦副。那么加入成功之后進(jìn)行
acquireQueued(Node, arg))```方法
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//自旋直到當(dāng)前線程之前的線程全部釋放鎖 這邊也是lock阻塞的原因
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
//如果它上一個節(jié)點(diǎn)是head并且獲取到鎖侦锯,把當(dāng)前節(jié)點(diǎn)設(shè)置成head
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 清除被取消的線程 并且把前一個節(jié)點(diǎn)設(shè)置成single 在下一次自旋進(jìn)行阻塞 等待喚醒
如果當(dāng)前線程中斷了 返回true 執(zhí)行selfInterrupt()中斷線程;
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
//出現(xiàn)異常
if (failed)
cancelAcquire(node);
}
}
以上就是非公平鎖的加鎖過程,下面介紹unlock()
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
//嘗試釋放鎖
if (tryRelease(arg)) {
//獲取當(dāng)前的頭結(jié)點(diǎn)
Node h = head;
if (h != null && h.waitStatus != 0)
//如果節(jié)點(diǎn)不為空 且狀態(tài)不是0 說明這是個執(zhí)行節(jié)點(diǎn) 下面釋放下一個節(jié)點(diǎn)的阻塞狀態(tài)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
//獲取當(dāng)前的狀態(tài)值減1
int c = getState() - releases;
//如果當(dāng)前線程不是aqs擁有者 拋出異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//如果減去1之后狀態(tài)值為0 說明當(dāng)前線程在aqs上的操作全部完成
//把狀態(tài)值歸0 返回true指向下一步 如果狀態(tài)值不為0 釋放失敗
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
private void unparkSuccessor(Node node) {
/*
*把當(dāng)前節(jié)點(diǎn)的狀態(tài)歸0
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
*獲取頭結(jié)點(diǎn)的下一個有效節(jié)點(diǎn)
* 如果節(jié)點(diǎn)存在 激活其中的線程 讓它去獲取鎖
*/
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);
}
我們在unlock的代碼中可以發(fā)現(xiàn)秦驯,它會激活處于等待中的下一個節(jié)點(diǎn)尺碰,讓它去競爭鎖。