AbstractQueuedSynchronizer浅析——同步
2019独角兽企业重金招聘Python工程师标准>>>
想研究并发编程快一年了,一直断断续续,没有重点,无所收获。写此文,以明志!
LockSupport,以后要重点看一下,在parkAndCheckInterrupt用到
conditionObject doReleaseShared
本文主要讲独占、共享地获取释放锁,condition没讲
先从数据结构开始,Node与Condition。源码是最好的老师
Node
static final class Node {/** 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;//节点处于独占模式的标志/** waitStatus value to indicate thread has cancelled */static final int CANCELLED = 1;//等待状态:线程取消了获取锁(独占\共享)的操作/** waitStatus value to indicate successor's thread needs unparking */static final int SIGNAL = -1;//后继(不一定是下一个)节点的线程需要unparking/** waitStatus value to indicate thread is waiting on condition */static final int CONDITION = -2;//线程在条件队列等待/*** waitStatus value to indicate the next acquireShared should* unconditionally propagate*/static final int PROPAGATE = -3;//获取锁的操作需要无条件传播(共享模式下),表示当前场景下后续的acquireShared能够得以执行/*** Status field, taking on only the values:* SIGNAL: The successor of this node is (or will soon be)* blocked (via park), so the current node must* unpark its successor when it releases or* cancels. To avoid races, acquire methods must* first indicate they need a signal,* then retry the atomic acquire, and then,* on failure, block.//只有当前状态为signal,才能获取锁,不然release\cancel会“忘了”unpark后面的线程* CANCELLED: This node is cancelled due to timeout or interrupt.* Nodes never leave this state. In particular,* a thread with cancelled node never again blocks.* CONDITION: This node is currently on a condition queue.* It will not be used as a sync queue node* until transferred, at which time the status* will be set to 0. (Use of this value here has* nothing to do with the other uses of the* field, but simplifies mechanics.)//表明节点在条件队列。当条件队列转为同步队列时,状态位置0(条件队列、同步队列可以参考wait/notify机制)* PROPAGATE: A releaseShared should be propagated to other* nodes. This is set (for head node only) in* doReleaseShared to ensure propagation* continues, even if other operations have* since intervened.//releaseShared后,状态传播(只有头结点会)* 0: None of the above //当前节点在sync队列中,等待着获取锁。** The values are arranged numerically to simplify use.* Non-negative values mean that a node doesn't need to* signal. So, most code doesn't need to check for particular* values, just for sign.//非负数表示当前节点不需要唤醒后继节点\传播状态** The field is initialized to 0 for normal sync nodes, and* CONDITION for condition nodes. It is modified using CAS* (or when possible, unconditional volatile writes).*/volatile int waitStatus;//等待状态是volatile,保证多线程间的可见性/*** Link to predecessor node that current node/thread relies on* for checking waitStatus. Assigned during enqueuing, and nulled* out (for sake of GC) only upon dequeuing. Also, upon* cancellation of a predecessor, we short-circuit while* finding a non-cancelled one, which will always exist* because the head node is never cancelled: A node becomes* head only as a result of successful acquire. A* cancelled thread never succeeds in acquiring, and a thread only* cancels itself, not any other node.*/volatile Node prev;//前驱节点,在出入queue时赋值,非cancel节点。一定存在,因为头结点非cancel/*** Link to the successor node that the current node/thread* unparks upon release. Assigned during enqueuing, adjusted* when bypassing cancelled predecessors, and nulled out (for* sake of GC) when dequeued. The enq operation does not* assign next field of a predecessor until after attachment,* so seeing a null next field does not necessarily mean that* node is at end of queue. However, if a next field appears* to be null, we can scan prev's from the tail to* double-check. The next field of cancelled nodes is set to* point to the node itself instead of null, to make life* easier for isOnSyncQueue.*/volatile Node next;//后继节点,释放锁时直接链到后继节点。入队时赋值,前驱节点 取消 时更改,出队时为null。//enq在入队时赋值,为null时不一定为tail。cancel节点的next为自身,以方便isOnSyncQueue/*** The thread that enqueued this node. Initialized on* construction and nulled out after use.*/volatile Thread thread;//使节点入队的线程,构造时初始化,use后为null/*** Link to next node waiting on condition, or the special* value SHARED. Because condition queues are accessed only* when holding in exclusive mode, we just need a simple* linked queue to hold nodes while they are waiting on* conditions. They are then transferred to the queue to* re-acquire. And because conditions can only be exclusive,* we save a field by using special value to indicate shared* mode.*/Node nextWaiter;//条件队列里的next,或SHARED.条件队列只会被独占模式访问,所以只需要简单的linkedQueue维护(因为线程安全)//也用它表示共享模式/*** Returns true if node is waiting in shared mode.*/final boolean isShared() {return nextWaiter == SHARED;}/*** Returns previous node, or throws NullPointerException if null.* Use when predecessor cannot be null. The null check could* be elided, but is present to help the VM.** @return the predecessor of this node*/final Node predecessor() throws NullPointerException {Node p = prev;if (p == null)throw new NullPointerException();elsereturn p;}Node() { // Used to establish initial head or SHARED marker}Node(Thread thread, Node mode) { // Used by addWaiterthis.nextWaiter = mode;//独占模式、共享模式、条件队列的next节点。入队使用this.thread = thread;}Node(Thread thread, int waitStatus) { // Used by Condition,如条件队列时使用this.waitStatus = waitStatus;this.thread = thread;}}
Node主要是由thread,waitStatus组成的数据结构,多个Node组成一个同步队列<acquire,release>,或条件队列<wait,notify>
ConditionObject
关于ConditionObject,我以后好好研究一下再讲
/*** Condition implementation for a {@link* AbstractQueuedSynchronizer} serving as the basis of a {@link* Lock} implementation.** <p>Method documentation for this class describes mechanics,* not behavioral specifications from the point of view of Lock* and Condition users. Exported versions of this class will in* general need to be accompanied by documentation describing* condition semantics that rely on those of the associated* {@code AbstractQueuedSynchronizer}.** <p>This class is Serializable, but all fields are transient,* so deserialized conditions have no waiters.*/public class ConditionObject implements Condition, java.io.Serializable {private static final long serialVersionUID = 1173984872572414699L;/** First node of condition queue. */private transient Node firstWaiter;/** Last node of condition queue. */private transient Node lastWaiter;/*** Creates a new {@code ConditionObject} instance.*/public ConditionObject() { }// Internal methods/*** Adds a new waiter to wait queue.* @return its new wait node*/private Node addConditionWaiter() {Node t = lastWaiter;// If lastWaiter is cancelled, clean out.if (t != null && t.waitStatus != Node.CONDITION) {unlinkCancelledWaiters();t = lastWaiter;}Node node = new Node(Thread.currentThread(), Node.CONDITION);if (t == null)firstWaiter = node;elset.nextWaiter = node;lastWaiter = node;return node;}/*** Removes and transfers nodes until hit non-cancelled one or* null. Split out from signal in part to encourage compilers* to inline the case of no waiters.* @param first (non-null) the first node on condition queue*/private void doSignal(Node first) {do {if ( (firstWaiter = first.nextWaiter) == null)lastWaiter = null;first.nextWaiter = null;} while (!transferForSignal(first) &&(first = firstWaiter) != null);}/*** Removes and transfers all nodes.* @param first (non-null) the first node on condition queue*/private void doSignalAll(Node first) {lastWaiter = firstWaiter = null;do {Node next = first.nextWaiter;first.nextWaiter = null;transferForSignal(first);first = next;} while (first != null);}/*** Unlinks cancelled waiter nodes from condition queue.* Called only while holding lock. This is called when* cancellation occurred during condition wait, and upon* insertion of a new waiter when lastWaiter is seen to have* been cancelled. This method is needed to avoid garbage* retention in the absence of signals. So even though it may* require a full traversal, it comes into play only when* timeouts or cancellations occur in the absence of* signals. It traverses all nodes rather than stopping at a* particular target to unlink all pointers to garbage nodes* without requiring many re-traversals during cancellation* storms.*/private void unlinkCancelledWaiters() {Node t = firstWaiter;Node trail = null;while (t != null) {Node next = t.nextWaiter;if (t.waitStatus != Node.CONDITION) {t.nextWaiter = null;if (trail == null)firstWaiter = next;elsetrail.nextWaiter = next;if (next == null)lastWaiter = trail;}elsetrail = t;t = next;}}// public methods/*** Moves the longest-waiting thread, if one exists, from the* wait queue for this condition to the wait queue for the* owning lock.** @throws IllegalMonitorStateException if {@link #isHeldExclusively}* returns {@code false}*/public final void signal() {if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignal(first);}/*** Moves all threads from the wait queue for this condition to* the wait queue for the owning lock.** @throws IllegalMonitorStateException if {@link #isHeldExclusively}* returns {@code false}*/public final void signalAll() {if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignalAll(first);}/*** Implements uninterruptible condition wait.* <ol>* <li> Save lock state returned by {@link #getState}.* <li> Invoke {@link #release} with saved state as argument,* throwing IllegalMonitorStateException if it fails.* <li> Block until signalled.* <li> Reacquire by invoking specialized version of* {@link #acquire} with saved state as argument.* </ol>*/public final void awaitUninterruptibly() {Node node = addConditionWaiter();int savedState = fullyRelease(node);boolean interrupted = false;while (!isOnSyncQueue(node)) {LockSupport.park(this);if (Thread.interrupted())interrupted = true;}if (acquireQueued(node, savedState) || interrupted)selfInterrupt();}/** For interruptible waits, we need to track whether to throw* InterruptedException, if interrupted while blocked on* condition, versus reinterrupt current thread, if* interrupted while blocked waiting to re-acquire.*//** Mode meaning to reinterrupt on exit from wait */private static final int REINTERRUPT = 1;/** Mode meaning to throw InterruptedException on exit from wait */private static final int THROW_IE = -1;/*** Checks for interrupt, returning THROW_IE if interrupted* before signalled, REINTERRUPT if after signalled, or* 0 if not interrupted.*/private int checkInterruptWhileWaiting(Node node) {return Thread.interrupted() ?(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :0;}/*** Throws InterruptedException, reinterrupts current thread, or* does nothing, depending on mode.*/private void reportInterruptAfterWait(int interruptMode)throws InterruptedException {if (interruptMode == THROW_IE)throw new InterruptedException();else if (interruptMode == REINTERRUPT)selfInterrupt();}/*** Implements interruptible condition wait.* <ol>* <li> If current thread is interrupted, throw InterruptedException.* <li> Save lock state returned by {@link #getState}.* <li> Invoke {@link #release} with saved state as argument,* throwing IllegalMonitorStateException if it fails.* <li> Block until signalled or interrupted.* <li> Reacquire by invoking specialized version of* {@link #acquire} with saved state as argument.* <li> If interrupted while blocked in step 4, throw InterruptedException.* </ol>*/public final void await() throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();Node node = addConditionWaiter();int savedState = fullyRelease(node);int interruptMode = 0;while (!isOnSyncQueue(node)) {LockSupport.park(this);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;if (node.nextWaiter != null) // clean up if cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);}/*** Implements timed condition wait.* <ol>* <li> If current thread is interrupted, throw InterruptedException.* <li> Save lock state returned by {@link #getState}.* <li> Invoke {@link #release} with saved state as argument,* throwing IllegalMonitorStateException if it fails.* <li> Block until signalled, interrupted, or timed out.* <li> Reacquire by invoking specialized version of* {@link #acquire} with saved state as argument.* <li> If interrupted while blocked in step 4, throw InterruptedException.* </ol>*/public final long awaitNanos(long nanosTimeout)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();Node node = addConditionWaiter();int savedState = fullyRelease(node);final long deadline = System.nanoTime() + nanosTimeout;int interruptMode = 0;while (!isOnSyncQueue(node)) {if (nanosTimeout <= 0L) {transferAfterCancelledWait(node);break;}if (nanosTimeout >= spinForTimeoutThreshold)LockSupport.parkNanos(this, nanosTimeout);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;nanosTimeout = deadline - System.nanoTime();}if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;if (node.nextWaiter != null)unlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);return deadline - System.nanoTime();}/*** Implements absolute timed condition wait.* <ol>* <li> If current thread is interrupted, throw InterruptedException.* <li> Save lock state returned by {@link #getState}.* <li> Invoke {@link #release} with saved state as argument,* throwing IllegalMonitorStateException if it fails.* <li> Block until signalled, interrupted, or timed out.* <li> Reacquire by invoking specialized version of* {@link #acquire} with saved state as argument.* <li> If interrupted while blocked in step 4, throw InterruptedException.* <li> If timed out while blocked in step 4, return false, else true.* </ol>*/public final boolean awaitUntil(Date deadline)throws InterruptedException {long abstime = deadline.getTime();if (Thread.interrupted())throw new InterruptedException();Node node = addConditionWaiter();int savedState = fullyRelease(node);boolean timedout = false;int interruptMode = 0;while (!isOnSyncQueue(node)) {if (System.currentTimeMillis() > abstime) {timedout = transferAfterCancelledWait(node);break;}LockSupport.parkUntil(this, abstime);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;if (node.nextWaiter != null)unlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);return !timedout;}/*** Implements timed condition wait.* <ol>* <li> If current thread is interrupted, throw InterruptedException.* <li> Save lock state returned by {@link #getState}.* <li> Invoke {@link #release} with saved state as argument,* throwing IllegalMonitorStateException if it fails.* <li> Block until signalled, interrupted, or timed out.* <li> Reacquire by invoking specialized version of* {@link #acquire} with saved state as argument.* <li> If interrupted while blocked in step 4, throw InterruptedException.* <li> If timed out while blocked in step 4, return false, else true.* </ol>*/public final boolean await(long time, TimeUnit unit)throws InterruptedException {long nanosTimeout = unit.toNanos(time);if (Thread.interrupted())throw new InterruptedException();Node node = addConditionWaiter();int savedState = fullyRelease(node);final long deadline = System.nanoTime() + nanosTimeout;boolean timedout = false;int interruptMode = 0;while (!isOnSyncQueue(node)) {if (nanosTimeout <= 0L) {timedout = transferAfterCancelledWait(node);break;}if (nanosTimeout >= spinForTimeoutThreshold)LockSupport.parkNanos(this, nanosTimeout);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;nanosTimeout = deadline - System.nanoTime();}if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;if (node.nextWaiter != null)unlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);return !timedout;}// support for instrumentation/*** Returns true if this condition was created by the given* synchronization object.** @return {@code true} if owned*/final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {return sync == AbstractQueuedSynchronizer.this;}/*** Queries whether any threads are waiting on this condition.* Implements {@link AbstractQueuedSynchronizer#hasWaiters(ConditionObject)}.** @return {@code true} if there are any waiting threads* @throws IllegalMonitorStateException if {@link #isHeldExclusively}* returns {@code false}*/protected final boolean hasWaiters() {if (!isHeldExclusively())throw new IllegalMonitorStateException();for (Node w = firstWaiter; w != null; w = w.nextWaiter) {if (w.waitStatus == Node.CONDITION)return true;}return false;}/*** Returns an estimate of the number of threads waiting on* this condition.* Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength(ConditionObject)}.** @return the estimated number of waiting threads* @throws IllegalMonitorStateException if {@link #isHeldExclusively}* returns {@code false}*/protected final int getWaitQueueLength() {if (!isHeldExclusively())throw new IllegalMonitorStateException();int n = 0;for (Node w = firstWaiter; w != null; w = w.nextWaiter) {if (w.waitStatus == Node.CONDITION)++n;}return n;}/*** Returns a collection containing those threads that may be* waiting on this Condition.* Implements {@link AbstractQueuedSynchronizer#getWaitingThreads(ConditionObject)}.** @return the collection of threads* @throws IllegalMonitorStateException if {@link #isHeldExclusively}* returns {@code false}*/protected final Collection<Thread> getWaitingThreads() {if (!isHeldExclusively())throw new IllegalMonitorStateException();ArrayList<Thread> list = new ArrayList<Thread>();for (Node w = firstWaiter; w != null; w = w.nextWaiter) {if (w.waitStatus == Node.CONDITION) {Thread t = w.thread;if (t != null)list.add(t);}}return list;}}
Field
/*** Head of the wait queue, lazily initialized. Except for* initialization, it is modified only via method setHead. Note:* If head exists, its waitStatus is guaranteed not to be* CANCELLED.* 等待队列的head,懒加载。除了初始化,只会被setHead修改。如果存在head,他的waiitStatus绝对不是canceled*/private transient volatile Node head;/*** Tail of the wait queue, lazily initialized. Modified only via* method enq to add new wait node.* 等待队列的tali,懒加载。只会被enq修改*/private transient volatile Node tail;/*** The synchronization state.同步器的状态*/private volatile int state;
下面重点讲方法
Method
扩展——非抽象方法
以下5个protected方法,不是传统的abstract方法,是为了让子类选择性实现,如:writeLock只需要实现tryAcquire/tryRelease这种独占锁的方法,readLock只需要实现tryAcquireShared/tryReleaseShared这种共享锁的方法。
// Main exported methods 主要暴露出去的方法,给了子类实现上的灵活性/*** Attempts to acquire in exclusive mode. This method should query* if the state of the object permits it to be acquired in the* exclusive mode, and if so to acquire it.* 以独占的模式获取锁。需要查看 状态 来决定是否能获取锁* <p>This method is always invoked by the thread performing* acquire. If this method reports failure, the acquire method* may queue the thread, if it is not already queued, until it is* signalled by a release from some other thread. This can be used* to implement method {@link Lock#tryLock()}.* 被尝试获取锁的线程调用,会进入\停在队列,直到被其他线程release后signal。该方法可以实现Lock.tryLock* <p>The default* implementation throws {@link UnsupportedOperationException}.** @param arg the acquire argument. This value is always the one* passed to an acquire method, or is the value saved on entry* to a condition wait. The value is otherwise uninterpreted* and can represent anything you like.* @return {@code true} if successful. Upon success, this object has* been acquired.* @throws IllegalMonitorStateException if acquiring would place this* synchronizer in an illegal state. This exception must be* thrown in a consistent fashion for synchronization to work* correctly.* @throws UnsupportedOperationException if exclusive mode is not supported*/protected boolean tryAcquire(int arg) {throw new UnsupportedOperationException();}/*** Attempts to set the state to reflect a release in exclusive* mode.** <p>This method is always invoked by the thread performing release.** <p>The default implementation throws* {@link UnsupportedOperationException}.** @param arg the release argument. This value is always the one* passed to a release method, or the current state value upon* entry to a condition wait. The value is otherwise* uninterpreted and can represent anything you like.* @return {@code true} if this object is now in a fully released* state, so that any waiting threads may attempt to acquire;* and {@code false} otherwise.* @throws IllegalMonitorStateException if releasing would place this* synchronizer in an illegal state. This exception must be* thrown in a consistent fashion for synchronization to work* correctly.* @throws UnsupportedOperationException if exclusive mode is not supported*/protected boolean tryRelease(int arg) {throw new UnsupportedOperationException();}/*** Attempts to acquire in shared mode. This method should query if* the state of the object permits it to be acquired in the shared* mode, and if so to acquire it.** <p>This method is always invoked by the thread performing* acquire. If this method reports failure, the acquire method* may queue the thread, if it is not already queued, until it is* signalled by a release from some other thread.** <p>The default implementation throws {@link* UnsupportedOperationException}.** @param arg the acquire argument. This value is always the one* passed to an acquire method, or is the value saved on entry* to a condition wait. The value is otherwise uninterpreted* and can represent anything you like.* @return a negative value on failure; zero if acquisition in shared* mode succeeded but no subsequent shared-mode acquire can* succeed; and a positive value if acquisition in shared* mode succeeded and subsequent shared-mode acquires might* also succeed, in which case a subsequent waiting thread* must check availability. (Support for three different* return values enables this method to be used in contexts* where acquires only sometimes act exclusively.) Upon* success, this object has been acquired.* @throws IllegalMonitorStateException if acquiring would place this* synchronizer in an illegal state. This exception must be* thrown in a consistent fashion for synchronization to work* correctly.* @throws UnsupportedOperationException if shared mode is not supported*/protected int tryAcquireShared(int arg) {throw new UnsupportedOperationException();}/*** Attempts to set the state to reflect a release in shared mode.** <p>This method is always invoked by the thread performing release.** <p>The default implementation throws* {@link UnsupportedOperationException}.** @param arg the release argument. This value is always the one* passed to a release method, or the current state value upon* entry to a condition wait. The value is otherwise* uninterpreted and can represent anything you like.* @return {@code true} if this release of shared mode may permit a* waiting acquire (shared or exclusive) to succeed; and* {@code false} otherwise* @throws IllegalMonitorStateException if releasing would place this* synchronizer in an illegal state. This exception must be* thrown in a consistent fashion for synchronization to work* correctly.* @throws UnsupportedOperationException if shared mode is not supported*/protected boolean tryReleaseShared(int arg) {throw new UnsupportedOperationException();}/*** Returns {@code true} if synchronization is held exclusively with* respect to the current (calling) thread. This method is invoked* upon each call to a non-waiting {@link ConditionObject} method.* (Waiting methods instead invoke {@link #release}.)** <p>The default implementation throws {@link* UnsupportedOperationException}. This method is invoked* internally only within {@link ConditionObject} methods, so need* not be defined if conditions are not used.** @return {@code true} if synchronization is held exclusively;* {@code false} otherwise* @throws UnsupportedOperationException if conditions are not supported*/protected boolean isHeldExclusively() {throw new UnsupportedOperationException();}
独占模式——获取锁
// Queuing utilities/*** The number of nanoseconds for which it is faster to spin* rather than to use timed park. A rough estimate suffices* to improve responsiveness with very short timeouts.*/static final long spinForTimeoutThreshold = 1000L;//自旋阈值/*** Acquires in exclusive mode, ignoring interrupts. Implemented* by invoking at least once {@link #tryAcquire},* returning on success. Otherwise the thread is queued, possibly* repeatedly blocking and unblocking, invoking {@link* #tryAcquire} until success. This method can be used* to implement method {@link Lock#lock}.* 独占模式获取锁,不响应 中断 。至少调用一次tryAcquire,如果返回true,结束。否则,线程入队,在blocking-unblocking* 之间徘徊,直到tryAcquire成功。* @param arg the acquire argument. This value is conveyed to* {@link #tryAcquire} but is otherwise uninterpreted and* can represent anything you like.*/public final void acquire(int arg) {//tryAcquire由子类继承if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}/*** Creates and enqueues node for current thread and given mode.* 为当前线程以给定的模式(独占、共享)创建node,并enqueue,入队列* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared* @return the new node*/private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);//构造新节点,有独占、共享,两种模式// Try the fast path of enq; backup to full enq on failure,fast-fail机制,先部分调用enq,fail后full调用enqNode pred = tail;//获取tail节点if (pred != null) {//如果存在node.prev = pred;//prev,volatile变量if (compareAndSetTail(pred, node)) {//以cas方式(保证线程安全)设置尾节点,成功pred.next = node;//设置两个节点的双向关系 node1<=>node2return node;}}enq(node);return node;}/*** Inserts node into queue, initializing if necessary. See picture above.* @param node the node to insert* @return node's predecessor*/private Node enq(final Node node) {for (;;) {//自旋Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {//需要for自旋与cas操作 保证线程安全t.next = node;return t;}}}}/*** Acquires in exclusive uninterruptible mode for thread already in* queue. Used by condition wait methods as well as acquire.* 在独占模式中不可中断地获取锁。也可用在条件队列中* @param node the node* @param arg the acquire argument* @return {@code true} if interrupted while waiting*/final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {//可以看到,这里是一个自旋,acquire方法会“重复”在这里,直到获取锁成功final Node p = node.predecessor();//node.previf (p == head && tryAcquire(arg)) {//如果node的前驱节点时头结点,且获取锁成功setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}/*** Checks and updates status for a node that failed to acquire.* Returns true if thread should block. This is the main signal* control in all acquire loops. Requires that pred == node.prev.* 检查并更新status of node that fails to acquire.* @param pred node's predecessor holding status* @param node the node* @return {@code true} if thread should block*/private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {int ws = pred.waitStatus;//make sure that pred is node.prev : ws是在for里循环调用的,不用担心现在的值马上会被修改if (ws == Node.SIGNAL)/** This node has already set status asking a release* to signal it, so it can safely park.* node的前驱节点时signal,当pred做release操作时,会unpark node,所以node可以安全地park*/return true;if (ws > 0) {/** Predecessor was cancelled. Skip over predecessors and* indicate retry.* 前驱节点已经取消,prev往前移*/do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);pred.next = node;} else {/** waitStatus must be 0 or PROPAGATE. Indicate that we* need a signal, but don't park yet. Caller will need to* retry to make sure it cannot acquire before parking.* waitStatus must be 0 or PROPAGATE.但不用立即park线程,在for里再一次尝试获取锁* 可以发现这个cas没有直接包含在for循环里(调用shouldParkAfterFailedAcquire会自旋),不在乎一次的成败*/compareAndSetWaitStatus(pred, ws, Node.SIGNAL);}return false;}/*** Convenience method to interrupt current thread.*/static void selfInterrupt() {Thread.currentThread().interrupt();}/*** Convenience method to park and then check if interrupted** @return {@code true} if interrupted*/private final boolean parkAndCheckInterrupt() {LockSupport.park(this);return Thread.interrupted();}
LockSupport,以后要重点看一下
总结一下:先tryAcquire,成功则结束。失败,则先将当前线程包装成独占节点node,并尝试将node设为tail,从而加入等待队列(因为是多线程操作,直接加入等待队列会有问题,通过单次地成为tail,保证线程安全),如果没设成tail(多线程的复杂性),在for循环里设成tail。当加入队列后,在for循环里获取锁(自己成为头结点),如果没有获取锁,根据实际情况决定park,或者继续尝试获取锁。
独占模式——释放锁
/*** Releases in exclusive mode. Implemented by unblocking one or* more threads if {@link #tryRelease} returns true.* This method can be used to implement method {@link Lock#unlock}.** @param arg the release argument. This value is conveyed to* {@link #tryRelease} but is otherwise uninterpreted and* can represent anything you like.* @return the value returned from {@link #tryRelease}*/public final boolean release(int arg) {if (tryRelease(arg)) {//if tryRelease success,Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;}/*** Wakes up node's successor, if one exists.* 唤醒后继节点* @param node the node*/private void unparkSuccessor(Node node) {/** If status is negative (i.e., possibly needing signal) try* to clear in anticipation of signalling. It is OK if this* fails or if status is changed by waiting thread.*/int ws = node.waitStatus;if (ws < 0)compareAndSetWaitStatus(node, ws, 0);//不在for循环里,不要求成功/** Thread to unpark is held in successor, which is normally* just the next node. But if cancelled or apparently null,* traverse backwards from tail to find the actual* non-cancelled successor.*/Node s = node.next;if (s == null || s.waitStatus > 0) {//waitStatus>0 it has canceleds = 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);//唤醒在acquire里park住的线程}
如果tryRelease成功,唤醒后继节点(unpark在acuireQueue里park住的线程,让其进行下一次的for循环,final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) )。
共享模式获取锁
/*** Acquires in shared mode, ignoring interrupts. Implemented by* first invoking at least once {@link #tryAcquireShared},* returning on success. Otherwise the thread is queued, possibly* repeatedly blocking and unblocking, invoking {@link* #tryAcquireShared} until success.* 共享模式获取锁,不响应中断。失败后,进入队列,在blocking\unblocking之间徘徊,直到成功* @param arg the acquire argument. This value is conveyed to* {@link #tryAcquireShared} but is otherwise uninterpreted* and can represent anything you like.*/public final void acquireShared(int arg) {if (tryAcquireShared(arg) < 0)doAcquireShared(arg);}/*** Acquires in shared uninterruptible mode. do...实际执行体* @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);//tryAcquire - boolean tryAcquireShared - intif (r >= 0) {setHeadAndPropagate(node, r);p.next = null; // help GCif (interrupted)selfInterrupt();failed = false;return;}}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}/*** Creates and enqueues node for current thread and given mode.** @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared* @return the new node*/private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failureNode pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;}/*** Sets head of queue, and checks if successor may be waiting* in shared mode, if so propagating if either propagate > 0 or* PROPAGATE status was set.** @param node the node* @param propagate the return value from a tryAcquireShared*/private void setHeadAndPropagate(Node node, int propagate) {Node h = head; // Record old head for check below 老headsetHead(node);/** Try to signal next queued node if:* Propagation was indicated by caller,//调用者明示:传播* or was recorded (as h.waitStatus either before* or after setHead) 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 ||(h = head) == null || h.waitStatus < 0) {Node s = node.next;if (s == null || s.isShared())doReleaseShared();}}/*** Returns true if node is waiting in shared mode.*/final boolean isShared() {return nextWaiter == SHARED;}/*** Release action for shared mode -- signals successor and ensures* propagation. (Note: For exclusive mode, release just amounts* to calling unparkSuccessor of head if it needs signal.)* 共享模式释放锁 signal后继,并传播。独占模式只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 casesunparkSuccessor(h); //only signal 会唤醒后继}else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue; // loop on failed CAS}if (h == head) // loop if head changed 暗示:其他线程获取锁(setHead)break; //此期间其余线程没有获取锁,才会结束}}/*** Wakes up node's successor, if one exists.** @param node the node*/private void unparkSuccessor(Node node) {/** If status is negative (i.e., possibly needing signal) try* to clear in anticipation of signalling. It is OK if this* fails or if status is changed by waiting thread.*/int ws = node.waitStatus;if (ws < 0)compareAndSetWaitStatus(node, ws, 0);/** Thread to unpark is held in successor, which is normally* just the next node. But if cancelled or apparently null,* traverse backwards from tail to find the actual* non-cancelled successor.*/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);}
转载于:https://my.oschina.net/u/1380557/blog/793969
AbstractQueuedSynchronizer浅析——同步相关推荐
- 浅谈AQS(AbstractQueuedSynchronizer,同步队列)
1.1 同步队列:队列中存放排队等待锁的线程,每个线程放入队列时会被包装为Node类,如下图. 1.2 抢锁:调用lock方法,如果抢锁成功(CAS成功,或者是重入--state计数加1),那么in ...
- 来了!PostgreSQL 同步流复制原理和代码浅析,请签收
摘要: 数据库 ACID 中的持久化如何实现 数据库 ACID 里面的 D,持久化. 指的是对于用户来说提交的事务,数据是可靠的,即使数据库 crash了,在硬件完好的情况下,也能恢复回来.Postg ...
- Java Review - 并发编程_抽象同步队列AQS
文章目录 概述 AQS--锁的底层支持 state 的作用 ConditionObject 独占 VS 共享 独占方式下,获取与释放资源的流程 共享方式下,获取与释放资源的流程 Interruptib ...
- 谈谈CountDownLatch和CyclicBarrier
Java中CountDownLatch和CyclicBarrier都是用来做多线程同步的.下面分析一下他们功能的异同. CountDownLatch CountDownLatch基于AQS(同步器Ab ...
- 读-深入理解Java虚拟机(1-2章)随笔
笔者花了一个星期的晚上时间看完了前面三章,由于之前在其他博客看过JVM的东西,所以看起来比较快. 前l两章内容分别是--走近Java:Java内存区域与内存溢出异常.其中部分除黑色内容属于扩展性内容或 ...
- 并发编程笔记——第六章 Java并发包中锁原理剖析
一.LockSupport工具类 JDK中的rt.jar包里的LockSupport是个工具类,它的主要作用是挂起和唤醒线程,该工具类是创建锁和其他同步类的基础.LockSupport类与每个使用它的 ...
- JAVA 拾遗 --Future 模式与 Promise 模式
JAVA 拾遗 --Future 模式与 Promise 模式 写这篇文章的动机,是缘起于微信闲聊群的一场讨论,粗略整理下,主要涉及了以下几个具体的问题: 同步,异步,阻塞,非阻塞的关联及区别. JA ...
- Future 模式与 Promise 模式
这篇文章主要涉及了以下几个具体的问题: 同步,异步,阻塞,非阻塞的关联及区别. JAVA 中有 callback 调用吗? jdk 包中的 Future 怎么用? Future 模式和 Promise ...
- 冲大厂:Java并发六十问,快来看看你会多少道
这篇文章有点长,四万字,图文详解六十道Java并发面试题.人已经肝麻了,大家可以点赞.收藏慢慢看!扶我起来,我还能肝! 基础 1.并行跟并发有什么区别? 从操作系统的角度来看,线程是CPU分配的最小单 ...
最新文章
- 软件测试培训需要学习什么技术
- springboot自定义jar通过enable配置是否开启
- pytorch bert文本分类_一起读Bert文本分类代码 (pytorch篇 四)
- [新手-数据分析师]numpy学习笔记(2nd)
- 超级有意思的代码注释
- c语言读写nfc,Android NFC M1卡读写芯片卡读写(CPU卡读写)(RFID读写)
- python的GUI编程和tkinter学习笔记——第一个GUI程序
- PAT学习资料汇总(PAT甲级、PAT顶级、PAT考试经验)
- 信息学奥赛C++语言:换座位
- Qt之加减乘除四则运算-支持负数
- 块存储性能--阿里云ECS磁盘
- 如何防范和应对Redis勒索,腾讯云教你出招
- Hibernate多列作为联合主键(六)
- 卡巴斯基授权文件获取网站
- 什么是serialVersionUID?serialVersionUID详解
- 趣味编程:有A,B,C,D,E五人,每人额头上都帖了一张黑或白的纸
- 地理信息系统(GIS)与数字地球
- CAPM与多因子定价模型
- 免Root卸载系统预装应用
- 最新CcPay多商户个人收款码支付系统源码+UI很不错
热门文章
- ZendStudio8的注册码
- 微软总裁比尔.盖茨给即将走出学校、踏入社会的青年一代下列11点忠告
- oracle 取mac地址,java执行命令,得到Mac地址
- antd 能自适应吗_一种能自适应识别母线运行方式的备自投装置应用探讨
- php可以用水晶报表吗,什么是水晶报表与水晶报表功能分析
- java中类作为成员变量类型使用、接口作为成员变量类型使用、接口作为方法的参数或返回值使用
- $@ $# $2 $0 $* Linux 参数使用
- zabbix的入门到精通之zabbix的触发器Trigger
- 面试题,你觉得什么样的产品适合做成saas?
- 2022十大科技趋势