CountDownLatch

使用

  1. 构造时,指定一个int 门栓个数
  2. 线程A 执行cdt.await(),线程A会park 挂起
  3. 线程B 调用 cdt.coundDown(); 会打开一个门栓,直到门栓个数是0时,notify 所有park 的线程

主要方法

class CountDownLatch {
	public CountDownLatch(int count) {}

	public await() {}
	
	public coundDown() {}
}

原理

AbstractQueuedSynchronizer实现的

创建

class CDL {
	public CDL(int count) {
		. // count必须>0
		sync = new Sync(count);
	}

	class Sync extends AQS {
		Sync(int count) {
			setState(count);
		}
	}
}

await()

class CDL {
	void await() {
		sync.acquireSharedInterruptibly(1); //进入AQS里
	}
}
class AQS {
	// arg 没有用到。门栓数是保存到AQS.state里。
	// 判断门栓个数,为0则结束;不为0则 线程park
	void acquireSharedInterruptibly(int arg) { 
		if (Thread.interrupted()) {
			throw new .;
		}
		if () { // 如果门栓是0,则不进入if分支,此函数会结束。
			// 如果门栓数不是0,则进入if分支,线程park
			doAcquireSharedInterruptibly(arg);
		}
	}
}
  1. 门栓 != 0时,线程在for循环里park
  2. 调用 countDown() 方法,门栓 = 0 时,unpark head.next里的线程。
  3. head.next里的线程从for 循环里 parkAndCheckInterrupt() 处 继续执行。
class AQS {
	void doAcquireSharedInterruptibly(int arg) { //参数 arg 没有用
		// 1. 新建Node,这个Node.nextWaiter是 Node.EXCLUSIVE,Node.thread=Thread.currentThread()
		// 2. 把它添加到 队列尾巴 上。
		// 队列没有node时,head 和 tail 还是会指向一个初始化的Node
		Node node = addWaiter(Node.SHARED);
		
		try {
			for (;;) {
				Node p = node.predecessor(); 
				
				// unpark 唤醒后,如果本node == head.next,尝试执行
				if (p == head) {
					.
					if (r >= 0) { // r >=0 的含义就是 门栓=0
						// 把node设置成 head,并且再执行 doReleaseShared(),用以再unpark下一个thread
						setHeadAndPropagate(node, r);
						p.next = null;
						return;
					}
				}
				
				if (shouldParkAfterFailedAcquire(p, node) // node是本次的node,p=node.pre。true的条件是 p.wateStatus = Node.signal
						&& parkAndCheckInterrupt()) { // 当前线程park,等待唤醒
					throw new .;
				}
				
				
			}
		}
	}
}

countDown()

class CDL {
	void countDown() {
		sync.releaseShared(1); // AQS 里
	}
}
  1. 门栓数=0时,unpark head.next里的线程
class AQS {
	// 参数 arg 没用
	boolean releaseShared(int arg) {
		if (门栓-1后,是否为0) {
			// 门栓=0 时
			// unpark head.next里的线程
			doReleaseShared(); 
			return true;
		}
		return false;
	}
}
  1. unpark head.next里的线程
class AQS {
	void doReleaseShared() {
		for (;;) {
			Node h = head;
			if (h != null && h != tail) {
				int ws = h.waitStatus; // 在acquire 时,会把 head.waitStatus 设置为 Node.signal
				if (ws == Node.signal) {
					..
					unparkSuccessor(h); // successor是接班人的意思。 unpark head.next里的thread
				}
				...
			}
		}
	}
}
  1. unpark head.next里的线程,此时那个park的线程会在 doAcquireSharedInterruptibly() 里恢复并继续执行
class AQS {
	void unparkSuccessor(Node node) {
		...
		Node s = node.next;
		...
		if (s != null) {
			LockSupport.unpark(s.thread);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值