AQS的功能可以分為兩類:獨(dú)占與共享;如ReentrantLock利用了其獨(dú)占功能,CountDownLatch,Semaphore利用了其共享功能嗓违。
AQS的靜態(tài)內(nèi)部類Node里有兩個(gè)變量,獨(dú)占鎖與共享鎖在創(chuàng)建自己的節(jié)點(diǎn)時(shí)(addWaiter方法)用于表明身份,它們會(huì)被賦值給Node的nextWaiter變量图贸。
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
獨(dú)占鎖
獨(dú)占鎖就是每次只允許一個(gè)線程執(zhí)行蹂季,當(dāng)前線程執(zhí)行完會(huì)release將同步狀態(tài)歸零,再喚醒后繼節(jié)點(diǎn)疏日,這里通過(guò)自定義tryAcquire來(lái)實(shí)現(xiàn)公平與非公平(即是否允許插隊(duì))偿洁;
acquire & release
//成功代表同步狀態(tài)的變更,排斥其他線程沟优;否則加入等待隊(duì)列
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//歸零同步狀態(tài)涕滋,喚醒后繼節(jié)點(diǎn)
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
這里通過(guò)同步狀態(tài)來(lái)實(shí)現(xiàn)獨(dú)占功能。
共享鎖
如Semaphore挠阁,CountDownLatch宾肺,它們調(diào)用的是AQS里的acquireSharedInterruptibly與releaseShared;實(shí)現(xiàn)自己的tryAcquireShared與tryReleaseShared侵俗,這里便體現(xiàn)了獨(dú)占與共享的不同锨用,獨(dú)占鎖的tryAcquire,tryRelease返回boolean代表同步狀態(tài)更改的成功與否隘谣;tryAcquireShared返回int值增拥,tryAcquireShared返回0代表當(dāng)前線程能夠執(zhí)行,但之后的將會(huì)進(jìn)入等待隊(duì)列中寻歧;返回正數(shù)直接執(zhí)行掌栅,之后的線程可能也可以直接執(zhí)行;
以Semphore的非公平鎖為例熄求,如果當(dāng)前正在執(zhí)行的線程數(shù)小于限制值渣玲,就CAS更改同步狀態(tài)值逗概,線程直接執(zhí)行弟晚。返回負(fù)數(shù)代表正在執(zhí)行的線程數(shù)達(dá)到允許值。
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
Semphore限制同時(shí)執(zhí)行的線程數(shù),當(dāng)一個(gè)線程acquire成功
acquireShared
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//這里對(duì)中斷的處理也不同卿城,共享式的線程被喚醒后發(fā)現(xiàn)中斷標(biāo)記后枚钓,會(huì)直接拋中斷異常
//而獨(dú)占鎖采用的中斷策略是恢復(fù)中斷標(biāo)記,也就是交給調(diào)用方去處理中斷
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
releaseShared
tryReleaseShared由子類實(shí)現(xiàn)瑟押,返回boolean搀捷,以Semphore為例
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
當(dāng)一個(gè)線程執(zhí)行完會(huì)增加我們的同步狀態(tài)值,返回true多望,之后doReleaseShared喚醒head.next節(jié)點(diǎn)里的線程嫩舟。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
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);
}
doReleaseShared在之前介紹Semaphore里說(shuō)過(guò);若有后繼節(jié)點(diǎn)就喚醒它怀偷;若沒(méi)有(即ws == 0家厌,因?yàn)閣aitStatus的值是后繼節(jié)點(diǎn)賦予的)則將head節(jié)點(diǎn)waitStatus改為PROPAGATE,之后進(jìn)入的節(jié)點(diǎn)會(huì)將此head的狀態(tài)改為SIGNAL椎工,具體實(shí)現(xiàn)在shouldParkAfterFailedAcquire里饭于。
總結(jié)
獨(dú)占與共享最大不同就在各自的tryacquire里,對(duì)于獨(dú)占來(lái)說(shuō)只有true或false维蒙,只有一個(gè)線程得以執(zhí)行任務(wù)掰吕;而對(duì)于共享鎖的tryAcquireShared來(lái)說(shuō),線程數(shù)沒(méi)達(dá)到限制都可以直接執(zhí)行颅痊。
但本質(zhì)上都是對(duì)AQS同步狀態(tài)的修改殖熟,一個(gè)是0與1之間,另一個(gè)允許更多而已斑响。