CountDownLatch解析

逃离我推掉我的手 2022-03-17 06:18 506阅读 0赞

1.CountDownLatch的await方法

  1. public void await() throws InterruptedException {
  2. sync.acquireSharedInterruptibly(1);
  3. }

然后调用

  1. public final void acquireSharedInterruptibly(int arg)
  2. throws InterruptedException {
  3. if (Thread.interrupted())
  4. throw new InterruptedException();
  5. if (tryAcquireShared(arg) < 0)
  6. doAcquireSharedInterruptibly(arg);
  7. }

再调用

  1. protected int tryAcquireShared(int acquires) {
  2. return (getState() == 0) ? 1 : -1;
  3. }

countdown的state数量(也是CountDownLatch的count数量)不为0 所以返回 -1,然后调用doAcquireSharedInterruptibly,将当前线程加入到阻塞的线程并将当前线程阻塞

  1. private void doAcquireSharedInterruptibly(int arg)
  2. throws InterruptedException {
  3. final Node node = addWaiter(Node.SHARED);
  4. boolean failed = true;
  5. try {
  6. for (;;) {
  7. final Node p = node.predecessor();
  8. if (p == head) {
  9. int r = tryAcquireShared(arg);
  10. if (r >= 0) {
  11. setHeadAndPropagate(node, r);
  12. p.next = null; // help GC
  13. failed = false;
  14. return;
  15. }
  16. }
  17. if (shouldParkAfterFailedAcquire(p, node) &&
  18. parkAndCheckInterrupt())
  19. throw new InterruptedException();
  20. }
  21. } finally {
  22. if (failed)
  23. cancelAcquire(node);
  24. }
  25. }

然后把当前线程加到阻塞的队列中,并把当前线程给 阻塞掉

  1. private final boolean parkAndCheckInterrupt() {
  2. LockSupport.park(this);
  3. return Thread.interrupted();
  4. }

2.CountDownLatch的countdown方法

  1. public void countDown() {
  2. sync.releaseShared(1);
  3. }

调用

  1. public final boolean releaseShared(int arg) {
  2. if (tryReleaseShared(arg)) {
  3. doReleaseShared();
  4. return true;
  5. }
  6. return false;
  7. }

首先调用,tryReleaseShared采用cas 循环自旋的方式将当前的state 减去1,如果已经被别的线程减到到0了,返回false(防止多个线程都重复唤醒被阻塞的线程),首次减到0的时候返回true,否则也返回fasle

  1. protected boolean tryReleaseShared(int releases) {
  2. // Decrement count; signal when transition to zero
  3. for (;;) {
  4. int c = getState();
  5. if (c == 0)
  6. return false;
  7. int nextc = c-1;
  8. if (compareAndSetState(c, nextc))
  9. return nextc == 0;
  10. }
  11. }

tryReleaseShared 返回true的时候开始调用 doReleaseShared()方法,将队列中被阻塞的线程唤醒

  1. private void doReleaseShared() {
  2. for (;;) {
  3. Node h = head;
  4. if (h != null && h != tail) {
  5. int ws = h.waitStatus;
  6. if (ws == Node.SIGNAL) {
  7. if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
  8. continue; // loop to recheck cases
  9. unparkSuccessor(h);
  10. }
  11. else if (ws == 0 &&
  12. !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
  13. continue; // loop on failed CAS
  14. }
  15. if (h == head) // loop if head changed
  16. break;
  17. }
  18. }

发表评论

表情:
评论列表 (有 0 条评论,506人围观)

还没有评论,来说两句吧...

相关阅读