共享模式acquire实现流程
上文我们讲授了AbstractQueuedSynchronizer独有模式的acquire实现流程,本文一气呵成继承看一下AbstractQueuedSynchronizer共享模式acquire的实现流程。持续两篇文章的进修,也可以比拟独有模式acquire和共享模式acquire的区别,劳务派遣管理系统,加深对付AbstractQueuedSynchronizer的领略。
先看一下共享模式acquire的实现,要领为acquireShared和acquireSharedInterruptibly,两者不同不大,区别就在于后者有间断处理惩罚,以acquireShared为例:
public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); }
这里就能看出第一个不同来了:独有模式acquire的时候子类重写的要领tryAcquire返回的是boolean,等于否tryAcquire乐成;共享模式acquire的时候,返回的是一个int型变量,判定是否<0。doAcquireShared要领的实现为:
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); } }
我们来阐明一下这段代码做了什么:
确实,共享模式下的acquire和独有模式下的acquire大部门逻辑差不多,最大的不同在于tryAcquireShared乐成之后,独有模式的acquire是直接将当前节点配置为head节点即可,共享模式会执行setHeadAndPropagate要领,顾名思义,即在配置head之后多执行了一步propagate操纵。setHeadAndPropagate要领源码为:
private void setHeadAndPropagate(Node node, int propagate) { Node h = head; // Record old head for check below setHead(node); /* * Try to signal next queued node if: * Propagation was indicated by caller, * or was recorded (as h.waitStatus) by a previous operation * (note: this uses sign-check of waitStatus because * PROPAGATE status may transition to SIGNAL.) * and * The next node is waiting in shared mode, * or we don't know, because it appears null * * The conservatism in both of these checks may cause * unnecessary wake-ups, but only when there are multiple * racing acquires/releases, so most need signals now or soon * anyway. */ if (propagate > 0 || h == null || h.waitStatus < 0) { Node s = node.next; if (s == null || s.isShared()) doReleaseShared(); } }
第3行的代码配置重设head,第2行的代码由于第3行的代码要重设head,因此先界说一个Node型变量h得到原head的地点,这两行代码很简朴。
第19行~第23行的代码是独有锁和共享锁最纷歧样的一个处所,我们再看独有锁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); } }
这意味着独有锁某个节点被叫醒之后,它只需要将这个节点配置成head就完事了,而共享锁纷歧样,某个节点被配置为head之后,假如它的后继节点是SHARED状态的,那么将继承通过doReleaseShared要领实验往后叫醒节点,实现了共享状态的向后流传。
共享模式release实现流程