b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

semaphore AQS(AbstractQueuedSynchronizer)源代码分析(三)——共享的aquire(2)

电脑杂谈  发布时间:2018-02-13 15:13:49  来源:网络整理

这段代码的执行逻辑与非共享模式的执行逻辑相似,这里不赘述。我们重点关注的是“当再次尝试,获取成功之后的setHeadAndPropagate方法的处理”。这个方法的处理是与非共享模式不一样的。setHeadAndPropagate的代码:

private void setHeadAndPropagate(Node node, int propagate) {
	Node h = head; // Record old head for check below
	
	//替换head节点。因为head表示当前正在执行的节点。
	//节点已经获取成功,则将会被执行,所以需要替换head
	setHead(node); 
	 
	if (propagate > 0 || h == null || h.waitStatus < 0 ||
		(h = head) == null || h.waitStatus < 0) {
		Node s = node.next;
		if (s == null || s.isShared()) //获取当前节点的下一个节点,判断是否是共享模式的节点
		
			//如果是共享模式的节点,则唤醒nextNode。doReleaseShared方法其实就是semaphore.release()
			//的内部实现。具体的实现,下文release方法中进行说明
			doReleaseShared(); 
	}
}
可以看到,在非共享模式中,如果获取成功后,仅仅只是直接替换了head节点,并没有唤醒nextNode节点的操作;而对于共享模式,则进行了唤醒操作。所以这个唤醒的操作将是共享模式的核心。

二、共享的release方法

代码:

public final boolean releaseShared(int arg) {
	if (tryReleaseShared(arg)) {  //尝试释放,如果释放成功,则执行doReleaseShared
		doReleaseShared();
		return true;
	}
	return false;
}

类Semaphore.Sync中的tryReleaseShared(arg)方法的实现如下:

protected final boolean tryReleaseShared(int releases) {
	for (;;) {
		int current = getState();
		int next = current + releases; //acquire是减少,release就是增加
		if (next < current) // overflow
			throw new Error("Maximum permit count exceeded");
		if (compareAndSetState(current, next))
			return true;
	}
}

接下来重点看一下doReleaseShared()方法:

private void doReleaseShared() {
	 
	for (;;) {
		Node h = head;
		if (h != null && h != tail) {
			int ws = h.waitStatus; //获取head节点的状态
			
			//判断head节点的状态,如果head节点的状态是SIGNAL,
			//表示head节点存在nextNode,需要唤醒nextNode
			if (ws == Node.SIGNAL) {   
			
				//先尝试修改head节点的状态,如果成功,则唤醒nextNode,如果失败,则继续尝试
				if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) 
					continue;            // loop to recheck cases
				unparkSuccessor(h);
			}
			else if (ws == 0 &&  
					 !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
				continue;     
				
			//如果head节点的状态是0,则尝试修改为PROPAGATE;
			//PROPAGATE表示下一个节点可以无条件的进行acquire,也就是下一次acquire一定会成功,即信号量充足
			//如果head节点的状态是PROPAGATE,则不做任何处理,直接退出循环返回。
		}
		if (h == head) //跳出循环
			break;
	}
}

以上基本就是AQS的共享模式的实现。对于doReleaseShared()方法中对于head节点的SIGNAL状态判断,很可能会有疑惑。疑惑在于:head节点什么时候才会为SIGNAL状态呢?

?? ?? ?? 对于这个疑惑,首先先要知道SIGNAL状态表示什么。SIGNAL状态表示节点有nextNode,即有后续处理节点。在当前的节点处理完之后,需要唤醒nextNode。以Semaphore类举例:

?? ?? ??当我们的5个信号量都用完的时候,有新的线程进入(下文称作newThread)。此时,newThread就会被挂起。这个挂起的过程需要经过两个个步骤:

1、在node队列增加一个node,且这个node是共享模式的

2、判断新增加的node的prevNode(前节点)是否为SIGNAL状态。如果是SIGNAL状态,则直接挂起线程;如果不是SGINAL状态,则先将前一个node的状态修改SIGNAL状态,再挂起线程。

关于上面两个步骤的实现在shouldParkAfterFailedAcquire方法和doAcquireShared方法中


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-75627-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    • 格桑央宗
      格桑央宗

      在这个颜即正义的大网络时代

    每日福利
    热点图片
    拼命载入中...