以我第一次讀源碼的順序瘩蚪。
創(chuàng)建鎖:
private static final long serialVersionUID = 7373984872572414699L;
private final Sync sync;
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
//主要邏輯都是基于這個大名鼎鼎的AQS
abstract static class Sync extends AbstractQueuedSynchronizer {}
加鎖
public void lock() {
sync.lock();
}
非公平鎖:
final void lock() {
// 直接通過cas獲取鎖宴霸,state == 0鎖可用
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
//如果沒有拿到則
else
acquire(1);
}
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
public final void acquire(int arg) {
// addWaiter就是把當(dāng)前線程封裝成node妓柜,添加到等待隊列的尾端
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//這里沒太想明白雀摘,什么狀態(tài)才會需要自我中斷
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// state == 0,沒有人占用鎖
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;
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 如果符合park的條件苦掘,其實就是前序node狀態(tài)為-1换帜,則進入parkAndCheckInterrupt()函數(shù),其中調(diào)用LockSupport.park()實現(xiàn)線程的阻塞鹤啡;否則就嘗試賦值前序狀態(tài)至-1惯驼,然后再次嘗試獲取鎖,如果沒拿到則進入阻塞揉忘。
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
// ws > 0 -> ws = CANCEL跳座,把cancel節(jié)點從隊列中移除
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 如果前序的狀態(tài)為0或-2,-3泣矛,則嘗試將前序變?yōu)?1
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
//這里沒太想明白疲眷,當(dāng)前線程什么時候會設(shè)置interrupt呢?
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
獲取鎖的邏輯都是在AQS里您朽,這里就需要看一下AQS的結(jié)構(gòu):維護了一個雙向鏈表狂丝,用于存放等待鎖的線程node,包括head哗总,tail几颜。
sync的狀態(tài)status,0表示空閑讯屈,>0有占用蛋哭。
還有這幾個offset變量,存儲的是通過unsafe.objectFieldOffset方法獲取到的各變量的內(nèi)存偏移地址涮母。
AQS繼承AOS谆趾,AOS有個重要的變量exclusiveOwnerThread,存儲的就是當(dāng)前持有鎖的線程叛本。
waitStatus包括如下幾種狀態(tài):
int CANCELLED = 1 //節(jié)點從同步隊列中取消
int SIGNAL = -1 //后繼線程處于等待狀態(tài)跷叉,如果當(dāng)前節(jié)點釋放同步狀態(tài)會通知后繼線程,使其能夠運行
int CONDITION = -2//當(dāng)前節(jié)點進入等待隊列中
int PROPAGATE = -3//表示下一次共享式同步狀態(tài)獲取將會無條件傳播下去
int INITIAL = 0;//初始狀態(tài)
公平鎖:
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
公平鎖相對于非公平鎖营搅,就多了一個邏輯hasQueuedPredecessors()云挟。
對于非公平鎖,當(dāng)某個線程嘗試獲取鎖的時候转质,如果正好碰到前一個線程釋放了鎖园欣,通過cas拿到鎖,那就可以了峭拘。而對于公平鎖俊庇,是按照AQS隊列的先后順序來獲取鎖的狮暑。
釋放鎖
公平和非公平鎖的釋放邏輯是一致的
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
// 如果釋放成功后state==0,則return true
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;
}
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//倒敘尋找離head最近的可喚醒線程
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);
}