Java multi-threading (8)

Java multi-threading (8)

AQS

AbstractQueuedSynchronized (AQS), its name class, an abstract type synchronizer queue, the AQS defines a set of multi-threaded access to shared resources frame synchronization, synchronization based many implementations rely on it, such as the commonly used ReentrantLock / Semaphore / CountDownLatch ...

Two-way queue

Node node

AQS is a bidirectional FIFO queue, the internal nodes by the recording head of the queue head and tail, and the tail element, the element is a column of type Node, wherein the Node Thread variable used to store the AQS enters the inside of the threaded columns; node Node sHARED used to mark the inside of the thread is blocked after acquiring the shared resource into the suspended queue AQS; eXCLUSIVE for the thread to be suspended after acquiring exclusive resources into AQS queue; waitStatus recording standby state of the current thread can (the thread was canceled) was CANCELLED, SIGNAL (thread needs to be woken up), cONDITION (thread waits in queue condition inside), (required to notify other nodes release shared resources) PROPAGATE

Look Node node structure:
Here Insert Picture Description

In which the meaning of the four constants:

        //waitStatus值为1时表示该线程节点已释放(超时、中断),已取消的节点不会再阻塞
        static final int CANCELLED =  1;

        //waitStatus为-1时表示该线程的后续线程需要阻塞,即只要前置节点释放锁,就会通知标识为 SIGNAL 状态的后续节点的线程 
        static final int SIGNAL    = -1;

        //waitStatus为-2时,表示该线程在condition队列中阻塞(Condition有使用)
        static final int CONDITION = -2;

        //waitStatus为-3时,表示该线程以及后续线程进行无条件传播(CountDownLatch中有使用)共享模式下, PROPAGATE 状态的线程处于可运行状态 
        static final int PROPAGATE = -3;


This two-way queue is essentially a doubly linked list, Node is the list of nodes:

Here Insert Picture Description

5 properties

waitStatus :

waitStatus current node is a wait state flag, the flag determines what state the node is in the present case.

first:

Address saved synchronous thread queue front node

next :

Saved address subsequent synchronization node thread queue

thread :

The main thread synchronization queue thread information storage

nextWaiter:

In AQS condition queue is a list of stored one-way, with nextWaiter connected. The same data structure blocking queue and the queue is not used in conditions

nextWaiter mark is actually in the wake of the node depending on the state of the node to determine whether conditions based on wakeup node (Note: For example, A current node is shared, then it's this field is shared, that is waiting on the queue, a successor node if the node is shared node a is not shared, then it is not a sHARED nextWaiter constant, i.e. it is exclusive).
:

  • SHARED (shared mode): Direct wake up the next node

  • EXCLUSIVE (Exclusive): Wait for the current thread of execution after the completion wake

Analytical method


        // 构造方法为空参构造,一般用于创建head节点,或者为nextWaiter设置共享标志。
        Node() {   
        }

        // 构造方法用于创建一个带有条件队列的节点
        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }
        
        // 用于创建一个带有初始等waitStatus的节点
        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }

        // 检查当前节点是否为共享节点
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        // 用来查找前置节点是否存在,相当于为前置节点查空
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

ConditionObject

ConditionObject AQS has an internal class, to achieve binding thread synchronization lock, ConditionObject direct access to the inside of the AQS variable objects, such as state and AQS queue state value. ConditionObject a condition variable, corresponding to a condition of each condition variable queue (singly linked list queue), after being used to store await method calls blocked condition variable thread

Look ConditionObject structure:

Here Insert Picture Description

Defined Variables

         //条件(等待)队列的第一个节点
        private transient Node firstWaiter;
        //条件(等待)队列的最后一个节点
        private transient Node lastWaiter;

method


   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是否在同步队列中
             * 
             * 这里有个理解难点,为什么需要判断节点Node是否在同步队列中呢?
             * 因为当线程调用signal或signalAll时,会从firstWaiter节点开始,
             * 将节点依次从等待队列中移除,并通过enq方法重新添加到同步队列中
             * 
             * 因此当其他线程调用signal或者signalAll方法时,该线程可能从条件(等待)队列中移除,并重新加入到同步队列中
             * 1. 如果没有,则阻塞当前线程,同时调用checkInterruptWhileWaiting检测当前线程在等待过程中是否发生中断,
             *    设置interruptMode表示中断状态。
             * 2. 如果isOnSyncQueue方法判断出当前线程已经处于同步队列中了,则跳出while循环
            */
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            //利用acquireQueued方法循环尝试获取同步状态(锁)
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();//将等待队列中,不是Node.CONDITION状态的节点移除
            if (interruptMode != 0)//判断中断状态,
                reportInterruptAfterWait(interruptMode);
        }




  //将当前线程生成的节点加入到链表末尾,并返回该节点
        private Node addConditionWaiter() {
            Node t = lastWaiter;
            // 如果最后一个节点
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();//这个方法就是将等待队列中不是Node.CONDTION状态的节点从链表中移除
                t = lastWaiter;
            }
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }


//遍历一次CONDITION链表,删除状态为CANCELLED的节点。
	private void unlinkCancelledWaiters() {
			//首节点
            Node t = firstWaiter;
            Node trail = null;
            while (t != null) {
				//下一个节点
                Node next = t.nextWaiter;
				//如果t的状态是cancelled的,则需要删除t
                if (t.waitStatus != Node.CONDITION) {
				//清除t的nextWaiter连接
                    t.nextWaiter = null;
					//删除的是首节点
                    if (trail == null)
                        firstWaiter = next;
                    else
					//直接将前一个节点的连接指向该节点的下一个节点
                        trail.nextWaiter = next;
					//设置新的尾节点
                    if (next == null)
                        lastWaiter = trail;
                }
				//状态为CONDITION的节点不需要清除
                else
                    trail = t;
                t = next;
            }
    }


//完全释放锁,释放成功则返回,失败则将当前节点的状态设置成cancelled表示当前节点失效
	final int fullyRelease(Node node) {
        boolean failed = true;
        try {
		//获取当前锁重入的次数
            int savedState = getState();
			//释放锁
            if (release(savedState)) {
			//释放成功
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
		//释放锁失败,则当前节点的状态变为cancelled(此时该节点在CONDITION队列中)
            if (failed)
                node.waitStatus = Node.CANCELLED;
        }
    }


//尝试释放锁,释放成功则调用unparkSuccessor唤醒后继节点
	public final boolean release(int arg) {
	//调用tryRelease释放锁。
        if (tryRelease(arg)) {
		//释放成功,则查看head节点状态,如果不为null且状态不为0(为0表示没有后继或者当前节点已经unparkSuccessor过),则调用unparkSuccessor唤醒后继节点
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }


//判断该节点是否在CLH队列中
	final boolean isOnSyncQueue(Node node) {
	//如果该节点的状态为CONDITION(该状态只能在CONDITION队列中出现,CLH队列中不会出现CONDITION状态),或者该节点的prev指针为null,则该节点一定不在CLH队列中
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
		//如果该节点的next(不是nextWaiter,next指针在CLH队列中指向下一个节点)状态不为null,则该节点一定在CLH队列中
        if (node.next != null) // If has successor, it must be on queue
            return true;
        //否则只能遍历CLH队列(从尾节点开始遍历)查找该节点
        return findNodeFromTail(node);
    }


//从尾节点开始,使用prev指针,遍历整个CLH队列
	private boolean findNodeFromTail(Node node) {
        Node t = tail;
		//从尾节点开始,使用prev指针,开始遍历整个CLH队列
        for (;;) {
		//找到该节点
            if (t == node)
                return true;
			//遍历完成,没有找到该节点
            if (t == null)
                return false;
            t = t.prev;
        }
    }


//在等待后发生中断,在此处根据interruptMode统一处理
	 private void reportInterruptAfterWait(int interruptMode)
            throws InterruptedException {
            if (interruptMode == THROW_IE)
                throw new InterruptedException();
            else if (interruptMode == REINTERRUPT)
                selfInterrupt();
}


awaitNanos: if the current thread interrupt occurs, an exception is thrown; overtime is forced to transfer to CLH queue (but nextWaiter CONDITION connection in the queue did not cancel)

And await difference:

  • (1) expires, the force transfer from the node to a queue CONDITION CLH queue.

  • (2) blocking call is LockSupport.parkNanos (this, nanosTimeout), with time

  • (3) should be updated each cycle nanosTimeout, if time-out occurs (1)

public final long awaitNanos(long nanosTimeout)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
			//新创建一个CONDITION状态的节点,并加入队列尾部
            Node node = addConditionWaiter();
			//node(此时处于CLH队列队首)释放占有的锁(在CLH队列中出队了),并且唤醒后继节点
            int savedState = fullyRelease(node);
			//根据nanosTimeout,计算deadline
            final long deadline = System.nanoTime() + nanosTimeout;
            int interruptMode = 0;
			//检测当前节点是否处于CLH队列中,没有则park当前线程,等待signal唤醒(从而将node节点从CONDITION队列中transfer到CLH队列中)
            while (!isOnSyncQueue(node)) {
			//如果超时,则调用transferAfterCancelledWait将当前Node强制transfer到CLH队列中
                if (nanosTimeout <= 0L) {
                    transferAfterCancelledWait(node);
                    break;
                }
				//nanosTimeout大于spinForTimeoutThreshold,则调用parkNanos等待nanosTimeout时间
                if (nanosTimeout >= spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
				//park的过程中发生中断,则跳出循环
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
				//更新nanosTimeout
                nanosTimeout = deadline - System.nanoTime();
            }
			//出了while循环,代表线程被唤醒,并且已经将该node从CONDITION队列transfer到了CLH队列中,或者发生中断
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
			//该节点调用transferAfterCancelledWait添加到CLH队列中的,此时该节点的nextWaiter不为null,需要调用unlinkCancelledWaiters将该节点从CONDITION队列中删除
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
			//统一处理上面发生的中断或者异常情况。
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
			//返回距离超时还剩多长时间
            return deadline - System.nanoTime();
        }
	final boolean transferAfterCancelledWait(Node node) {
	//将该节点状态由CONDITION变成0,调用enq将该节点从CONDITION队列添加到CLH队列中(但是在CONDITION队列中的nextWaiter连接并没有取消)
        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
            enq(node);
            return true;
        }
        //循环检测该node是否已经成功添加到CLH队列中
        while (!isOnSyncQueue(node))
            Thread.yield();
        return false;
    }


awaitUntil: do not wake up in time before the deadline, the forced transfer to CLH queue (but nextWaiter connection CONDITION queue did not cancel), an interrupt occurs an exception is thrown


public final boolean awaitUntil(Date deadline)
                throws InterruptedException {
				//获取绝对时间
            long abstime = deadline.getTime();
            if (Thread.interrupted())
                throw new InterruptedException();
			//新new一个node,添加到CLH队列的尾部
            Node node = addConditionWaiter();
			//释放锁
            int savedState = fullyRelease(node);
            boolean timedout = false;
            int interruptMode = 0;
			//循环检测该node是否已经成功添加到CLH队列中
            while (!isOnSyncQueue(node)) {
			//超时,强制transfer到CLH队列中(但是在CONDITION队列中的nextWaiter连接并没有取消)
                if (System.currentTimeMillis() > abstime) {
                    timedout = transferAfterCancelledWait(node);
                    break;
                }
				//park到abstime时间
                LockSupport.parkUntil(this, abstime);
				//发生异常,跳出循环
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
			//已经在CLH队列中了,或者抛出了异常
			//调用acquireQueued(同步阻塞方法)在CLH队列中获取锁
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
			//该节点调用transferAfterCancelledWait添加到CLH队列中的,此时该节点的nextWaiter不为null,需要调用unlinkCancelledWaiters将该节点从CONDITION队列中删除
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
			//统一处理上面发生的中断或者异常情况。
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
			//返回是否超时
            return !timedout;
        }

await (long time, TimeUnit unit): interrupt exception is thrown; CLH timeout cast into the queue (nextWaiter CONDITION connection in the queue is not canceled, while in case CONDITION CLH queues and queues)


public final boolean await(long time, TimeUnit unit)
                throws InterruptedException {
            long nanosTimeout = unit.toNanos(time);
            if (Thread.interrupted())
                throw new InterruptedException();
			//新new一个node,添加到CONDITION队列末尾
            Node node = addConditionWaiter();
			//释放锁(此节点在CLH队列中拥有锁,此时是CLH队列头结点)并唤醒后继节点。
            int savedState = fullyRelease(node);
			//计算deadline
            final long deadline = System.nanoTime() + nanosTimeout;
            boolean timedout = false;
            int interruptMode = 0;
			//检测当前节点是否处于CLH队列中,没有则park当前线程,等待signal唤醒(从而将node节点从CONDITION队列中transfer到CLH队列中)
            while (!isOnSyncQueue(node)) {
                if (nanosTimeout <= 0L) {
                    timedout = transferAfterCancelledWait(node);
                    break;
                }
				//park
                if (nanosTimeout >= spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
				//更新nanosTimeout
                nanosTimeout = deadline - System.nanoTime();
            }
			//在CLH队列中获取锁,或者发生中断
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null)
                unlinkCancelledWaiters();
			//统一处理上面发生的中断或者异常情况。
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return !timedout;
        }

awaitUninterruptibly: Ignore interrupt latency

public final void awaitUninterruptibly() {
	//将该线程封装成node,新节点的状态为CONDITION,添加到队列尾部
            Node node = addConditionWaiter();
			//在CLH队列首部释放占有的锁
            int savedState = fullyRelease(node);
            boolean interrupted = false;
			//循环检测该node是否已经成功添加到CLH队列中
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
				//用interrupted保存中断标志,不抛出异常
                if (Thread.interrupted())
                    interrupted = true;
            }
			//在CLH队列中获取锁 或者 interrupted发生中断了,则调用selfInterrupt发生中断
			//acquireQueued是一个阻塞方法
            if (acquireQueued(node, savedState) || interrupted)
                selfInterrupt();
        }

signal: a first queue for CONDITION CONDITION status of the node (the node and the preceding node state CANCELLED CONDITION dequeued from the queue), the node is added to the end of the queue from CONDITION CLH queue, the node needs to be set at the same time in the state of CLH queue predecessor node (if the node is a precursor to the precursor state or cancelled node performs CAS operation fails, call park operation here wake up that thread, otherwise set signal node status precursor of success in CLH queue, then do not wake up the thread here, wake-up work to the precursor node, may be less a park and unpark operations)


//唤醒CONDITION队列中首部的第一个CONDITION状态的节点
	public final void signal() {
			//判断锁是否被当前线程独占,如果不是,则当前线程不能signal其他线程
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
			//CONDITION队列不为null,则doSignal方法将唤醒CONDITION队列中所有的节点线程
            if (first != null)
                doSignal(first);
        }
	//对CONDITION队列中从首部开始的第一个CONDITION状态的节点,执行transferForSignal操作,将node从CONDITION队列中转换到CLH队列中,同时修改CLH队列中原先尾节点的状态
	private void doSignal(Node first) {
            do {
				//当前循环将first节点从CONDITION队列transfer到CLH队列
				//从CONDITION队列中删除first节点,调用transferForSignal将该节点添加到CLH队列中,成功则跳出循环
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }
	//两步操作,首先enq将该node添加到CLH队列中,其次若CLH队列原先尾节点为CANCELLED或者对原先尾节点CAS设置成SIGNAL失败,则唤醒node节点;否则该节点在CLH队列总前驱节点已经是signal状态了,唤醒工作交给前驱节点(节省了一次park和unpark操作)
	final boolean transferForSignal(Node node) {
        //如果CAS失败,则当前节点的状态为CANCELLED
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
		//enq将node添加到CLH队列队尾,返回node的prev节点p
        Node p = enq(node);
        int ws = p.waitStatus;
		//如果p是一个取消了的节点,或者对p进行CAS设置失败,则唤醒node节点,让node所在线程进入到acquireQueue方法中,重新进行相关操作
		//否则,由于该节点的前驱节点已经是signal状态了,不用在此处唤醒await中的线程,唤醒工作留给CLH队列中前驱节点
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }

signalAll: The CONDITION queue for any node out of the team, one by one to the end of CLH queue, and modify them in the state in the precursor node CLH queue, modify the signal success, you do not wake up the thread of the node in here, wake-up work to predecessor node CLH queue, or need to park here in the current thread.


public final void signalAll() {
	//查看当前线程是否独占锁,若不是,则当前线程没有权限执行signalAll操作,抛出异常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
			//唤醒CONDITION队列中所有节点,同时transfer到CLH队列中
            if (first != null)
                doSignalAll(first);
        }
	private void doSignalAll(Node first) {
            lastWaiter = firstWaiter = null;
            do {
				//将first节点从CONDITION队列中出队
                Node next = first.nextWaiter;
                first.nextWaiter = null;
				//将first节点在CLH队列中入队,同时可能需要执行unpark操作
                transferForSignal(first);
				//更新first的指向
                first = next;
            } while (first != null);
        }

Reference article

https://blog.csdn.net/u011470552/article/details/76571472

https://blog.csdn.net/zy1994hyq/article/details/84562475

He published 189 original articles · won praise 58 · views 180 000 +

Guess you like

Origin blog.csdn.net/Coder_py/article/details/104066175