組成結(jié)構(gòu)
ReentrantLock有三個(gè)內(nèi)部類诡宗,如下:
其中奸焙,F(xiàn)airSync是公平鎖汽烦,NofairSync是非公平鎖,F(xiàn)airSync與NofairSync都繼承于Sync嫁佳。
那么蝠引,什么是公平鎖與非公平鎖呢闷畸?
公平鎖:當(dāng)前線程不去獲得鎖播歼,而是進(jìn)入等待隊(duì)列的隊(duì)尾等待獲取鎖懊纳。
非公平鎖:先去嘗試獲取鎖乎完,如果獲取不到熏兄,再去隊(duì)尾排隊(duì)獲取鎖。
非公平鎖執(zhí)行代碼解析
當(dāng)調(diào)用lock()方法的時(shí)候树姨,默認(rèn)執(zhí)行的是非公平鎖的lock方法摩桶,很明顯,非公平鎖的效率是優(yōu)于公平鎖的
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
首先帽揪,根據(jù)CAS鎖判斷硝清,如果返回true,則當(dāng)前線程搶占這個(gè)鎖转晰,如果返回false芦拿,執(zhí)行acquire()方法士飒。
那么,什么是CAS鎖蔗崎?
CAS鎖
CAS酵幕,全稱為 Compare And Swap,是一條原子指令缓苛,直接由cpu來完成芳撒。進(jìn)入compareAndSetState()方法之中。
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
我們可以看到未桥,這個(gè)方法直接調(diào)用了Unsafe類的CompareAndSwapInt()方法笔刹,這是一個(gè)native方法,只有當(dāng)前值等于期望值的時(shí)候冬耿,返回true舌菜,如果不同,返回false亦镶,也就是說當(dāng)前線程進(jìn)入獲得鎖后酷师,其他線程需要判斷是否已經(jīng)改變,而且是在硬件層面實(shí)現(xiàn)的染乌,JVM也只是利用匯編來使用而已山孔。
但是CAS是有缺陷的,比如ABA的情況荷憋,cpu處理是需要時(shí)間的台颠,CAS操作需要讀取數(shù)值,與期望值對比勒庄,在這段時(shí)間內(nèi)串前,是可能出現(xiàn)其他線程進(jìn)入修改,又改回來的情況实蔽,解決方案:加入一個(gè)變量荡碾,每次線程進(jìn)入時(shí)加一,在線程進(jìn)入同時(shí)局装,判斷變量是否被修改過坛吁。
我們繼續(xù)回來
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
如果當(dāng)前鎖已經(jīng)被占用,就調(diào)用acquire()方法铐尚。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
嘗試獲取鎖拨脉,同時(shí)將,當(dāng)前線程加入等待隊(duì)列的末尾
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
tryAcquire()方法調(diào)用nofairTryAcquire()方法宣增。
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;
}
這個(gè)方法玫膀,判斷state的值,如果state的值為0的話爹脾,再進(jìn)行一次CAS鎖判斷帖旨,如果返回true箕昭,將當(dāng)前鎖設(shè)置為獨(dú)占鎖,為當(dāng)前線程所有解阅。
接下來進(jìn)入addWaiter()方法之中落竹,方法內(nèi)容如下:
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
判斷當(dāng)前隊(duì)列的尾節(jié)點(diǎn)是不是null,如果不為空瓮钥,將尾節(jié)點(diǎn)賦值給當(dāng)前節(jié)點(diǎn)的prev屬性,如果是空烹吵,說明這是一個(gè)空隊(duì)列碉熄,執(zhí)行enq()方法。
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
這是一個(gè)無限循環(huán)肋拔,如果尾節(jié)點(diǎn)為null锈津,進(jìn)行一次CAS判斷再次判斷Node對象是不是null,如果返回true凉蜂,尾節(jié)點(diǎn)即為頭結(jié)點(diǎn)琼梆。如果尾節(jié)點(diǎn)不為null,將當(dāng)前線程放入隊(duì)列窿吩,并且作CAS判斷茎杂,向隊(duì)列尾部添加當(dāng)前線程。
返回來纫雁,執(zhí)行acquireQueued():
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;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
當(dāng)且僅當(dāng)煌往,當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)等于頭結(jié)點(diǎn)時(shí),才能嘗試獲取鎖轧邪,當(dāng)二者都滿足時(shí)刽脖,把當(dāng)前節(jié)點(diǎn)設(shè)為頭結(jié)點(diǎn),當(dāng)前節(jié)點(diǎn)的next置為null忌愚,方便垃圾回收曲管,返回false。下面執(zhí)行方法shouldParkAfterFailedAcquire()判斷當(dāng)前線程是否可以被安全的掛起硕糊。
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 {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
院水!tryAcquire()與acquireQueued()方法返回true,執(zhí)行中斷简十。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
公平鎖部分與非公平鎖大同小異衙耕,在此不再贅述。