死磕JDK源码之CountDownLatch

源码分析

  1 package java.util.concurrent;
  2 
  3 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
  4 /*
  5 一个同步类工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成  CountDownLatch用一个给定的count初始化,
  6 await方法会一直阻塞直到调用countDown方法使当前的count值变成0,之后所有等待线程被释放,并且任何后续的await调用立即返回
  7 
  8 CountDownLatch初始化为N可以用来作一个线程等待,直到N个线程完成某项操作,或某些动作已经完成N次
  9 
 10 class Driver { // ...
 11    void main() throws InterruptedException {
 12      CountDownLatch startSignal = new CountDownLatch(1);
 13      CountDownLatch doneSignal = new CountDownLatch(N);
 14 
 15      for (int i = 0; i < N; ++i) // create and start threads
 16        new Thread(new Worker(startSignal, doneSignal)).start();
 17 
 18      doSomethingElse();            // don't let run yet
 19      startSignal.countDown();      // let all threads proceed
 20      doSomethingElse();
 21      doneSignal.await();           // wait for all to finish
 22    }
 23 }
 24 
 25 class Worker implements Runnable {
 26    private final CountDownLatch startSignal;
 27    private final CountDownLatch doneSignal;
 28    Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
 29      this.startSignal = startSignal;
 30      this.doneSignal = doneSignal;
 31    }
 32    public void run() {
 33      try {
 34        startSignal.await();
 35        doWork();
 36        doneSignal.countDown();
 37      } catch (InterruptedException ex) {} // return;
 38    }
 39 
 40    void doWork() { ... }
 41 }
 42 
 43 另一个典型的用法是把一个问题划分为N个部分,每一个部分用一个线程执行并把所有的线程
 44 放在Executor里面排队,执行完成就调用countDown方法,当所有子线程都执行完成,接应
 45 线程就可以通过await,即不被CountDownLatch的await方法阻塞了
 46 class Driver2 { // ...
 47    void main() throws InterruptedException {
 48      CountDownLatch doneSignal = new CountDownLatch(N);
 49      Executor e = ...
 50 
 51      for (int i = 0; i < N; ++i) // create and start threads
 52        e.execute(new WorkerRunnable(doneSignal, i));
 53 
 54      doneSignal.await();           // wait for all to finish
 55    }
 56 }
 57 
 58 class WorkerRunnable implements Runnable {
 59    private final CountDownLatch doneSignal;
 60    private final int i;
 61    WorkerRunnable(CountDownLatch doneSignal, int i) {
 62      this.doneSignal = doneSignal;
 63      this.i = i;
 64    }
 65    public void run() {
 66      try {
 67        doWork(i);
 68        doneSignal.countDown();
 69      } catch (InterruptedException ex) {} // return;
 70    }
 71 
 72    void doWork() { ... }
 73 }
 74 */
 75 
 76 // CountDownLatch底层由AQS支持
 77 public class CountDownLatch {
 78     // 内部类Sync
 79     private static final class Sync extends AbstractQueuedSynchronizer {
 80         private static final long serialVersionUID = 4982264981922014374L;
 81 
 82         Sync(int count) {
 83             setState(count);
 84         }
 85 
 86         int getCount() {
 87             return getState();
 88         }
 89 
 90         protected int tryAcquireShared(int acquires) {
 91             return (getState() == 0) ? 1 : -1;
 92         }
 93 
 94         protected boolean tryReleaseShared(int releases) {
 95             // Decrement count; signal when transition to zero
 96             for (; ; ) {
 97                 int c = getState();
 98                 if (c == 0)
 99                     return false;
100                 int nextc = c - 1;
101                 if (compareAndSetState(c, nextc))
102                     return nextc == 0;
103             }
104         }
105     }
106 
107     private final Sync sync;
108 
109     // 构造一个给定初始化为count的CountDownLatch count是线程能通过await方法之前需要调用countDown方法的次数
110     public CountDownLatch(int count) {
111         if (count < 0) throw new IllegalArgumentException("count < 0");
112         this.sync = new Sync(count);
113     }
114 
115     /*
116     使当前线程在倒计数为零前一直等待,除非线程被中断
117     如果当前count值为0,那么await方法会立即返回    如果当前count值大于0,当前线程会处于休眠状态直到:
118     1.由于调用countDown方法使得count值达到0    2.其他某个线程中断了当前线程
119     如果当前线程在进入await方法时已经设置了中断状态,或者在等待时被中断,则抛出InterruptedException异常,并清除当前线程的已中断状态
120      */
121     public void await() throws InterruptedException {
122         sync.acquireSharedInterruptibly(1);
123     }
124 
125     /*
126     使当前线程在倒计数为零前一直等待,除非线程被中断或超出了指定的等待时间
127     如果当前count值为0,那么await方法会立即返回true    如果当前count值大于0,当前线程会处于休眠状态直到:
128     1.由于调用countDown方法使得count值达到0    2.其他某个线程中断了当前线程    3.已超出指定的等待时间
129     如果计数达到零,那么await(long timeout, TimeUnit unit)会返回true
130     如果当前线程在进入await方法时已经设置了中断状态,或者在等待时被中断,则抛出InterruptedException异常,并清除当前线程的已中断状态
131     如果超出了指定的等待时间,则返回值为false,如果指定时间小于或等于0,那么await(long timeout, TimeUnit unit)根本不会等待,即不会阻塞主线程
132     timeout:要等待的最长时间    unit:timeout参数的时间单位
133 
134     如果计数到达零,则返回true    如果在计数到达零之前超过了等待时间,则返回false
135     */
136     public boolean await(long timeout, TimeUnit unit)
137             throws InterruptedException {
138         return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
139     }
140 
141     /*
142     递减闭锁的count值,如果计数到达零,则释放所有等待的线程
143     当前count值大于0,递减    当前count等于0,被阻塞的线程可以被调度了,且count值不会递减了
144     */
145     public void countDown() {
146         sync.releaseShared(1);
147     }
148 
149     public long getCount() {
150         return sync.getCount();
151     }
152 
153     public String toString() {
154         return super.toString() + "[Count = " + sync.getCount() + "]";
155     }
156 }

典型用法

 1 package test;
 2 
 3 import java.util.Random;
 4 import java.util.concurrent.CountDownLatch;
 5 
 6 /*
 7 CountDownLatch允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行
 8 count:初始化count数表示子线程计数器,只有为0时,主线程才会向下执行
 9 countDown()方法:计数器的值-1,如果计数达到0,释放所有等待的线程
10 await()方法:使主线程等到计数器为0才执行
11 
12 马拉松比赛,对参赛者的排名肯定是在所有参赛者跑完比赛之后进行,即N个线程执行操作,主线程等到N个子线程执行完毕之后再执行
13 */
14 public class CountDownLatchTest {
15     public static void main(String[] args) throws InterruptedException {
16         int threadCount = 10;
17         final CountDownLatch latch = new CountDownLatch(threadCount);
18 
19         for (int i = 0; i < threadCount; i++) {
20             new Thread(new Runnable() {
21                 @Override
22                 public void run() {
23                     System.out.println("线程" + Thread.currentThread().getId() + "开始出发");
24                     try {
25                         Thread.sleep(new Random().nextInt(1000));
26                     } catch (InterruptedException e) {
27                         e.printStackTrace();
28                     }
29                     System.out.println("线程" + Thread.currentThread().getId() + "已到达终点");
30                     latch.countDown();
31                 }
32             }).start();
33         }
34         latch.await();
35         System.out.println("所有线程已经执行完毕,开始计算排名");
36     }
37 
38 }

 

转载于:https://www.cnblogs.com/sakura1027/p/9397987.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值