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浅析——同步相关推荐

  1. 浅谈AQS(AbstractQueuedSynchronizer,同步队列)

    1.1 同步队列:队列中存放排队等待锁的线程,每个线程放入队列时会被包装为Node类,如下图.  1.2 抢锁:调用lock方法,如果抢锁成功(CAS成功,或者是重入--state计数加1),那么in ...

  2. 来了!PostgreSQL 同步流复制原理和代码浅析,请签收

    摘要: 数据库 ACID 中的持久化如何实现 数据库 ACID 里面的 D,持久化. 指的是对于用户来说提交的事务,数据是可靠的,即使数据库 crash了,在硬件完好的情况下,也能恢复回来.Postg ...

  3. Java Review - 并发编程_抽象同步队列AQS

    文章目录 概述 AQS--锁的底层支持 state 的作用 ConditionObject 独占 VS 共享 独占方式下,获取与释放资源的流程 共享方式下,获取与释放资源的流程 Interruptib ...

  4. 谈谈CountDownLatch和CyclicBarrier

    Java中CountDownLatch和CyclicBarrier都是用来做多线程同步的.下面分析一下他们功能的异同. CountDownLatch CountDownLatch基于AQS(同步器Ab ...

  5. 读-深入理解Java虚拟机(1-2章)随笔

    笔者花了一个星期的晚上时间看完了前面三章,由于之前在其他博客看过JVM的东西,所以看起来比较快. 前l两章内容分别是--走近Java:Java内存区域与内存溢出异常.其中部分除黑色内容属于扩展性内容或 ...

  6. 并发编程笔记——第六章 Java并发包中锁原理剖析

    一.LockSupport工具类 JDK中的rt.jar包里的LockSupport是个工具类,它的主要作用是挂起和唤醒线程,该工具类是创建锁和其他同步类的基础.LockSupport类与每个使用它的 ...

  7. JAVA 拾遗 --Future 模式与 Promise 模式

    JAVA 拾遗 --Future 模式与 Promise 模式 写这篇文章的动机,是缘起于微信闲聊群的一场讨论,粗略整理下,主要涉及了以下几个具体的问题: 同步,异步,阻塞,非阻塞的关联及区别. JA ...

  8. Future 模式与 Promise 模式

    这篇文章主要涉及了以下几个具体的问题: 同步,异步,阻塞,非阻塞的关联及区别. JAVA 中有 callback 调用吗? jdk 包中的 Future 怎么用? Future 模式和 Promise ...

  9. 冲大厂:Java并发六十问,快来看看你会多少道

    这篇文章有点长,四万字,图文详解六十道Java并发面试题.人已经肝麻了,大家可以点赞.收藏慢慢看!扶我起来,我还能肝! 基础 1.并行跟并发有什么区别? 从操作系统的角度来看,线程是CPU分配的最小单 ...

最新文章

  1. 软件测试培训需要学习什么技术
  2. springboot自定义jar通过enable配置是否开启
  3. pytorch bert文本分类_一起读Bert文本分类代码 (pytorch篇 四)
  4. [新手-数据分析师]numpy学习笔记(2nd)
  5. 超级有意思的代码注释
  6. c语言读写nfc,Android NFC M1卡读写芯片卡读写(CPU卡读写)(RFID读写)
  7. python的GUI编程和tkinter学习笔记——第一个GUI程序
  8. PAT学习资料汇总(PAT甲级、PAT顶级、PAT考试经验)
  9. 信息学奥赛C++语言:换座位
  10. Qt之加减乘除四则运算-支持负数
  11. 块存储性能--阿里云ECS磁盘
  12. 如何防范和应对Redis勒索,腾讯云教你出招
  13. Hibernate多列作为联合主键(六)
  14. 卡巴斯基授权文件获取网站
  15. 什么是serialVersionUID?serialVersionUID详解
  16. 趣味编程:有A,B,C,D,E五人,每人额头上都帖了一张黑或白的纸
  17. 地理信息系统(GIS)与数字地球
  18. CAPM与多因子定价模型
  19. 免Root卸载系统预装应用
  20. 最新CcPay多商户个人收款码支付系统源码+UI很不错

热门文章

  1. ZendStudio8的注册码
  2. 微软总裁比尔.盖茨给即将走出学校、踏入社会的青年一代下列11点忠告
  3. oracle 取mac地址,java执行命令,得到Mac地址
  4. antd 能自适应吗_一种能自适应识别母线运行方式的备自投装置应用探讨
  5. php可以用水晶报表吗,什么是水晶报表与水晶报表功能分析
  6. java中类作为成员变量类型使用、接口作为成员变量类型使用、接口作为方法的参数或返回值使用
  7. $@ $# $2 $0 $* Linux 参数使用
  8. zabbix的入门到精通之zabbix的触发器Trigger
  9. 面试题,你觉得什么样的产品适合做成saas?
  10. 2022十大科技趋势