java多线程系列7-AbstractQueuedSynchronizer源码分析

锁系列文章
java多线程系列8-ReentrantLock源码分析
java多线程系列9-共享锁Semaphore源码解析
java多线程系列10-读写锁ReentrantReadWriteLock源码分析

1. AbstractQueuedSynchronizer介绍

AbstractQueuedSynchronizer简称AQS,是java中锁或者同步器的核心类,可以毫不夸张的说这个类是了解并发框架中锁的基础。

2. AQS数据结构

AQS低层用的数据结构是一个双向链表,是队列的一种实现,也可看成是队列并且是FIFO。如下图所示,其中Sync queue,即同步队列,是双向链表,包括head结点和tail结点,head结点主要用作后续的调度。而Condition queue不是必须的,其是一个单向链表,只有当使用Condition时,才会存在此单向链表。并且可能会有多个Condition queue。
AQS数据结构

3. 源码分析

3.1AQS节点状态有五类

  • CANCELLED:节点等待超时或者中断。需要从队列中移除
  • SIGNAL:后续节点的等待状态,当前节点需要通知后续节点去运行
  • CONDITION :当前节点处于等待队列
  • PROPAGATE:共享,表示状态需要向后面的节点传播
  • 0:初始状态

3.2 AQS中使用的设计模式:

模板模式。AQS中获取锁有共享锁和独占锁,下面将对重点方法进行分析

3.3 acquire方法

(1)先看下acquire代码

				public final void acquire(int arg) {
			        if (!tryAcquire(arg) &&
			            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
			            selfInterrupt();
			    }

(2)tryAcquire方法,是需要子类实现的。作用是尝试获取锁
(3)addWaiter方法

			    private Node addWaiter(Node mode) {
			    	//mode实际是下一个在Condition条件上等待的节点
			        Node node = new Node(Thread.currentThread(), mode);
			        // Try the fast path of enq; backup to full enq on failure
			        Node pred = tail;
			        //如果队列不为空,尝试将当前节点添加到队列尾部
			        if (pred != null) {
			            node.prev = pred;
			            if (compareAndSetTail(pred, node)) {
			                pred.next = node;
			                return node;
			            }
			        }
			        //如果队列为空或者将当前节点添加到队列尾部失败
			        enq(node);
			        return node;
			    }

参数Node.EXCLUSIVE实际为null。

(4)enq方法就是自选将当前节点插入队列尾部

		    private Node enq(final Node node) {
		    	//自选将当前节点插入队列尾部
		        for (;;) {
		            Node t = tail;
		            //如果队列为空,创建队列,进入下次循环
		            if (t == null) { // Must initialize
		                if (compareAndSetHead(new Node()))
		                    tail = head;
		            } else {
		            //将当前节点尝试插入队列尾部
		                node.prev = t;
		                if (compareAndSetTail(t, node)) {
		                    t.next = node;
		                    return t;
		                }
		            }
		        }
		    }

(5)acquireQueued方法就是让将前节点获取锁,获取不到挂起线程

		    final boolean acquireQueued(final Node node, int arg) {
		        boolean failed = true;
		        try {
		            boolean interrupted = false;
		            for (;;) {
		            	//node节点的前一个节点
		                final Node p = node.predecessor();
		                //如果node节点是头结点后第一个节点,尝试获取锁
		                //成功获取锁,将node节点置为头结点
		                if (p == head && tryAcquire(arg)) {
		                    setHead(node);
		                    p.next = null; // help GC
		                    failed = false;
		                    return interrupted;
		                }
		                //shouldParkAfterFailedAcquire判断是否需要将当前线程挂起
		                //parkAndCheckInterrupt将当前线程挂起,并在唤醒后判断当前线程是否被中断
		                if (shouldParkAfterFailedAcquire(p, node) &&
		                    parkAndCheckInterrupt())
		                    interrupted = true;
		            }
		        } finally {
		            if (failed)
		            	//标示非正常退出,将当前节点标记为取消
		                cancelAcquire(node);
		        }
		    }

(6)shouldParkAfterFailedAcquire方法是判断当前节点是否可以挂起

		    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
		    	//当前节点的状态
		        int ws = pred.waitStatus;
		        if (ws == Node.SIGNAL)
		            /*
		             * This node has already set status asking a release
		             * to signal it, so it can safely park.
		             */
		        	//当前一个节点状态是SIGNAL,则当前节点可以挂起
		            return true;
		        if (ws > 0) {
		            /*
		             * Predecessor was cancelled. Skip over predecessors and
		             * indicate retry.
		             */
		        	//找到当前节点之前最近的有效节点
		            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.
		             */
		        	//将一个节点状态设值为SIGNAL
		            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
		        }
		        return false;
		    }

(7)parkAndCheckInterrupt方法挂起当前线程

		  private final boolean parkAndCheckInterrupt() {
		    	//挂起当前线程
		        LockSupport.park(this);
		        //当前线程是否被中断
		        return Thread.interrupted();
		    }

(8)cancelAcquire取消节点

	    private void cancelAcquire(Node node) {
	        // Ignore if node doesn't exist
	        if (node == null)
	            return;
	
	        node.thread = null;
	
	        // Skip cancelled predecessors
	        Node pred = node.prev;
	        //找到node节点之前最近的有效节点
	        while (pred.waitStatus > 0)
	            node.prev = pred = pred.prev;
	
	        // predNext is the apparent node to unsplice. CASes below will
	        // fail if not, in which case, we lost race vs another cancel
	        // or signal, so no further action is necessary.
	        Node predNext = pred.next;
	
	        // Can use unconditional write instead of CAS here.
	        // After this atomic step, other Nodes can skip past us.
	        // Before, we are free of interference from other threads.
	        //将当前节点状态设值为CANCELLED
	        node.waitStatus = Node.CANCELLED;
	
	        // If we are the tail, remove ourselves.
	        //当前节点为尾节点,将尾节点设值为前一个有效节点
	        if (node == tail && compareAndSetTail(node, pred)) {
	            compareAndSetNext(pred, predNext, null);
	        } else {
	            // If successor needs signal, try to set pred's next-link
	            // so it will get one. Otherwise wake it up to propagate.
	            int ws;
	            if (pred != head &&
	                ((ws = pred.waitStatus) == Node.SIGNAL ||
	                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
	                pred.thread != null) {
	                Node next = node.next;
	                if (next != null && next.waitStatus <= 0)
	                    compareAndSetNext(pred, predNext, next);
	            } else {
	            	//唤醒node节点后续的节点
	                unparkSuccessor(node);
	            }
	
	            node.next = node; // help GC
	        }
	    }

9)unparkSuccessor唤醒后续节点
这个方法属于释放锁方法,后续再分析

总结下,acquire方法大致流程如下:

  • tryAcquire尝试获取锁
  • 获取锁失败,addWaiter(Node.EXCLUSIVE)方法将当前线程打包成节点加入队列,并将当前线程挂起,等待被唤醒
  • 如果当前线程被不正常唤醒,则取消当前线程

获取锁流程

3.4 acquireInterruptibly方法

和acquire不同的是,该方法可以响应中断,抛出异常。

	  public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }
	    private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

3.5 tryAcquireNanos方法

tryAcquireNanos方法相对前两个是有了等待时长,等待时间一到,自动唤醒。并退出,也可以响应中断,抛出异常。

	   public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }
    private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

3.6 acquireShared方法

(1)acquireShared是共享模式下获取锁

			public final void acquireShared(int arg) {
		        if (tryAcquireShared(arg) < 0)
		            doAcquireShared(arg);
		    }

(2)tryAcquireShared是需要子类实现的方法
(3)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);
			        }
			    }

(4)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 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();
			        }
			    }

3.7 acquireSharedInterruptibly和tryAcquireSharedNanos方法

		这两个方法和上面类似,不再叙述

3.8 release

(1)release方法释放锁

				    public final boolean release(int arg) {
				        if (tryRelease(arg)) {
				            Node h = head;
				            if (h != null && h.waitStatus != 0)
				                unparkSuccessor(h);
				            return true;
				        }
				        return false;
				    }

(2) tryRelease方法是需要子类实现的方法
(3)unparkSuccessor方法唤醒后续节点

			  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;
		        //node节点(一般是头节点)状态不为取消状态或者初始状态,将状态设为初始状态0
		        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节点之后第一个有效节点
		        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);
		    }

3.9 releaseShared

(1)releaseShared共享模式下释放锁

			public final boolean releaseShared(int arg) {
		        if (tryReleaseShared(arg)) {
		            doReleaseShared();
		            return true;
		        }
		        return false;
		    }

(2)tryReleaseShared是子类需要实现的方法
(3)doReleaseShared方法

		 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;
		                //node节点为SIGNAL,将其设为0,并唤醒后续线程
		                if (ws == Node.SIGNAL) {
		                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
		                        continue;            // loop to recheck cases
		                    unparkSuccessor(h);
		                }
		                //node节点状态为0,将其设为PROPAGATE
		                else if (ws == 0 &&
		                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
		                    continue;                // loop on failed CAS
		            }
		            //头节点被改变继续循环
		            if (h == head)                   // loop if head changed
		                break;
		        }
		    }

3.10 await方法

(1)await方法

        public final void await() throws InterruptedException {
        	//相应中断
            if (Thread.interrupted())
                throw new InterruptedException();
            //将当前线程打包成一个节点,加入到Condition队列(不是同步队列)
            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;
            //清楚Condition队列中已经取消的节点
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            //是否需要发出报告异常
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }

(2)addConditionWaiter方法

		        private Node addConditionWaiter() {
		            Node t = lastWaiter;
		            // If lastWaiter is cancelled, clean out.
		            //如果Condition队列最后一个节点被取消,则清楚Condition队列中所有cancel节点
		            if (t != null && t.waitStatus != Node.CONDITION) {
		                unlinkCancelledWaiters();
		                t = lastWaiter;
		            }
		            //将当前线程构构造成一个condition节点,加入Condition队列
		            Node node = new Node(Thread.currentThread(), Node.CONDITION);
		            if (t == null)
		                firstWaiter = node;
		            else
		                t.nextWaiter = node;
		            lastWaiter = node;
		            return node;
		        }

(3)fullyRelease方法

		    final int fullyRelease(Node node) {
		        boolean failed = true;
		        try {
		        	//获取锁的状态,savedState为几代表线程重入锁几次
		            int savedState = getState();
		            //释放锁
		            if (release(savedState)) {
		                failed = false;
		                return savedState;
		            } else {
		                throw new IllegalMonitorStateException();
		            }
		        } finally {
		        	//失败,将当前节点设值为取消
		            if (failed)
		                node.waitStatus = Node.CANCELLED;
		        }
		    }

(4)isOnSyncQueue方法

		    final boolean isOnSyncQueue(Node node) {
		    	//如果node节点是CONDITION或者前一个节点为空,代表节点不在同步队列
		        if (node.waitStatus == Node.CONDITION || node.prev == null)
		            return false;
		        //节点有后续节点,代表在后续节点上
		        if (node.next != null) // If has successor, it must be on queue
		            return true;
		        /*
		         * node.prev can be non-null, but not yet on queue because
		         * the CAS to place it on queue can fail. So we have to
		         * traverse from tail to make sure it actually made it.  It
		         * will always be near the tail in calls to this method, and
		         * unless the CAS failed (which is unlikely), it will be
		         * there, so we hardly ever traverse much.
		         */
		        //从同步节点尾部找node节点
		        return findNodeFromTail(node);
		    }

(5)findNodeFromTail方法

			 private boolean findNodeFromTail(Node node) {
		        Node t = tail;
		        for (;;) {
		            if (t == node)
		                return true;
		            if (t == null)
		                return false;
		            t = t.prev;
		        }
		    }

(6)checkInterruptWhileWaiting方法

        private int checkInterruptWhileWaiting(Node node) {
        	//如果线程中断,判断是在signal之前中断还是之后,之前中断标示要抛出异常,之后中断标示要重新中转
            return Thread.interrupted() ?
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                0;
        }

(7)transferAfterCancelledWait方法

    final boolean transferAfterCancelledWait(Node node) {
    	//设置成功,代表是在signal之前中断,因为signal会将标志设为0
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
            enq(node);
            return true;
        }
        /*
         * If we lost out to a signal(), then we can't proceed
         * until it finishes its enq().  Cancelling during an
         * incomplete transfer is both rare and transient, so just
         * spin.
         */
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
    }

(8)unlinkCancelledWaiters方法

    private void unlinkCancelledWaiters() {
        	//将condition队列中cancel节点删除
            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;
                    else
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                }
                else
                    trail = t;
                t = next;
            }
        }

(9)reportInterruptAfterWait

        private void reportInterruptAfterWait(int interruptMode)
            throws InterruptedException {
            if (interruptMode == THROW_IE)
                throw new InterruptedException();
            else if (interruptMode == REINTERRUPT)
                selfInterrupt();
        }

总结下:

  • 线程调用wait方法,会将当前线程打包成一个condition节点
  • 当前线程释放锁
  • 判断当前线程是否在同步队列,不存在,挂起线程
  • 线程唤醒后,再次判断是否在同步队列,如果在同步队列,尝试获取锁,后面和同步队列逻辑一直

3.11 signal方法

(1)signal方法

        public final void signal() {
        	//如果不是独占锁抛出异常,Condition队列只有独占模式线程才会有
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            //唤醒第一个等待节点
            if (first != null)
                doSignal(first);
        }

(2)doSignal方法

	 private void doSignal(Node first) {
            do {
            	//将第一个wait节点下一个变成第一个wait节点
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
                //唤醒第一个节点
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }

(3)transferForSignal方法

    final boolean transferForSignal(Node node) {
        /*
         * If cannot change waitStatus, the node has been cancelled.
         */
    	//将当前节点的状态变为0
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;

        /*
         * Splice onto queue and try to set waitStatus of predecessor to
         * indicate that thread is (probably) waiting. If cancelled or
         * attempt to set waitStatus fails, wake up to resync (in which
         * case the waitStatus can be transiently and harmlessly wrong).
         */
        //将当前节点加入队列,加入队列后把前一个节点返回
        Node p = enq(node);
        int ws = p.waitStatus;
        //如果前一个节点是取消状态或者设为SIGNAL状态失败,唤醒当前线程
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值