共享模式與獨佔模式
AQL的內部隊列採用的是CLH隊列鎖模型,CLH隊列是由一個一個結點(Node)構成的。Node類中有兩個常量SHARE和EXCLUSIVE,顧名思義這兩個常量用於表示這個結點支持共享模式還是獨佔模式,共享模式指的是允許多個線程獲取同一個鎖而且可能獲取成功,獨佔模式指的是一個鎖如果被一個線程持有,其他線程必須等待。多個線程讀取一個文件可以採用共享模式,而當有一個線程在寫文件時不會允許另一個線程寫這個文件,這就是獨佔模式的應用場景。
- /** Marker to indicate a node is waiting in shared mode */
- static final Node SHARED = new Node();
- /** Marker to indicate a node is waiting in exclusive mode */
- static final Node EXCLUSIVE = null;
- final boolean isShared() {
- return nextWaiter == SHARED;
- }
共享模式下獲取鎖
- /**
- * Acquires in shared uninterruptible mode.
- * @param arg the acquire argument
- */
- private void doAcquireShared(int arg) {
- final Node node = addWaiter(Node.SHARED);
- boolean failed = true;
- try {
- boolean interrupted = false;
- for (;;) {
- final Node p = node.predecessor();
- if (p == head) {
- int r = tryAcquireShared(arg);
- if (r >= 0) {
- setHeadAndPropagate(node, r);
- p.next = null; // help GC
- if (interrupted)
- selfInterrupt();
- failed = false;
- return;
- }
- }
- if (shouldParkAfterFailedAcquire(p, node) &&
- parkAndCheckInterrupt())
- interrupted = true;
- }
- } finally {
- if (failed)
- cancelAcquire(node);
- }
- }
- if (propagate > 0 || h == null || h.waitStatus < 0) {
- Node s = node.next;
- if (s == null || s.isShared())
- doReleaseShared();
- }
共享模式下釋放鎖
- /**
- * Release action for shared mode -- signal successor and ensure
- * propagation. (Note: For exclusive mode, release just amounts
- * to calling unparkSuccessor of head if it needs signal.)
- */
- private void doReleaseShared() {
- /*
- * Ensure that a release propagates, even if there are other
- * in-progress acquires/releases. This proceeds in the usual
- * way of trying to unparkSuccessor of head if it needs
- * signal. But if it does not, status is set to PROPAGATE to
- * ensure that upon release, propagation continues.
- * Additionally, we must loop in case a new node is added
- * while we are doing this. Also, unlike other uses of
- * unparkSuccessor, we need to know if CAS to reset status
- * fails, if so rechecking.
- */
- 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);
- ......
- }
閉鎖(CountDownLatch)
- public void await() throws InterruptedException;
- public void countDown();
- public void await() throws InterruptedException {
- sync.acquireSharedInterruptibly(1);
- }
- if (shouldParkAfterFailedAcquire(p, node) &&
- parkAndCheckInterrupt())
- interrupted = true;
- public class CountDownLatch {
- private static final class Sync extends AbstractQueuedSynchronizer {
- Sync(int count) {
- setState(count);
- }
- ......
- }
- private final Sync sync;
- protected int tryAcquireShared(int acquires) {
- return (getState() == 0) ? 1 : -1;
- }
- ......
- }
- public void countDown() {
- sync.releaseShared(1);
- }
- //sync.releaseShared
- public final boolean releaseShared(int arg) {
- if (tryReleaseShared(arg)) {
- doReleaseShared();
- return true;
- }
- return false;
- }
- protected boolean tryReleaseShared(int releases) {
- // Decrement count; signal when transition to zero
- for (;;) {
- int c = getState();
- if (c == 0)
- return false;
- int nextc = c-1;
- if (compareAndSetState(c, nextc))
- return nextc == 0;
- }
- }