Java中CountDownLatch的使用和求多线程的运行时间

avatar 2017年11月3日16:40:17 评论 139 views

一、CountDownLatch的API

  • 构造方法摘要
    构造方法
    Constructor and Description
    CountDownLatch(int count)

    构造一个以给定计数 CountDownLatch CountDownLatch

  • 方法摘要

    所有方法 接口方法 具体的方法
    Modifier and Type Method and Description
    void await()

    导致当前线程等到锁存器计数到零,除非线程是 interrupted
    boolean await(long timeout, TimeUnit unit)

    使当前线程等待直到锁存器计数到零为止,除非线程为 interrupted或指定的等待时间过去。
    void countDown()

    减少锁存器的计数,如果计数达到零,释放所有等待的线程。
    long getCount()

    返回当前计数。
    String toString()

    返回一个标识此锁存器的字符串及其状态。

 

可以看到 CountDownLatch 类有两个最重要的方法

counttDown()   让计数值-1

await()               阻塞线程,直到计数值为0才唤醒

计数值最小为0

 

通过一个简单的例子可以验证上面的观点,不使用线程即可

测试1

  1. public static void main(String args[]) throws InterruptedException {
  2.         final CountDownLatch latch = new CountDownLatch(5);//设置计数值为5
  3.         System.out.println("开始你的表演!");
  4.         for(int i=0;i<3;i++) {
  5.             latch.countDown();
  6.             System.out.println("latch.getCount:"+latch.getCount());
  7.         }
  8.         latch.await();
  9.         System.out.println("再见吧,大海!");
  10.     }

运行结果如下

可见,当计数值为2的时候,遇到了 await(),此后将会一直处于等待状态(看左侧的红色按钮,表示程序还在等待)

测试2

  1. public static void main(String args[]) throws InterruptedException {
  2.     final CountDownLatch latch = new CountDownLatch(5);//设置计数值为5
  3.     System.out.println("开始你的表演!");
  4.     for(int i=0;i<8;i++) {
  5.         latch.countDown();
  6.         System.out.println("latch.getCount:"+latch.getCount());
  7.     }
  8.     latch.await();
  9.     System.out.println("再见吧,大海!");
  10. }

还是上面的代码,我们把 3 改成一个更大点的数,比如8

运行结果如下

结果说明,当计数值为0时,await()才会继续执行,而不会等待

同时,也发现计数值最小值为 0

 

二、求多线程的运行时间

CountDownLatch 允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。

这里我们可以实现一个功能,就是 “统计多线程的执行时间”,因为我们需要判断多线程是什么时候 start的,什么时候 end 的。而正好 CountDownLatch 类可以帮助我们知道什么时候结束。

让我们一步步实现它!

1、如何计算某段代码的运行时间

  1. public static void main(String args[]) {
  2.     long startTime = System.currentTimeMillis();
  3.     for(int i=0;i<1000;i++) {
  4.         System.out.println(i);
  5.     }
  6.     long endTime = System.currentTimeMillis();
  7.     System.out.println((endTime-startTime)+"ms");//13ms
  8. }

通过 System.currentTimeMillis() 方法获得当前系统时间(单位ms)

 

下面我们来求多线程的执行时间

2、失败的例子

  1. public static void main(String args[]) {
  2.       System.out.println("主线程开始");
  3.       long startTime = System.currentTimeMillis();
  4.       for(int i=0;i<5;i++) {
  5.           new Thread() {
  6.               @Override
  7.               public void run() {
  8.                   System.out.println(currentThread().getName()+"开始执行..");
  9.                   try {
  10.                       sleep(1000);
  11.                   } catch (InterruptedException e) {
  12.                       e.printStackTrace();
  13.                   }
  14.                   System.out.println(currentThread().getName()+"结束执行..");
  15.               }
  16.           }.start();
  17.       }
  18.       long endTime = System.currentTimeMillis();
  19.       System.out.println("多线程运行时间:"+(endTime-startTime)+"ms");//2ms
  20.       System.out.println("主线程结束");
  21.   }

运行结果如下

很显然,这是一个失败的答案。因为我们知道多线程(包括main线程)是抢占CPU执行资源的,所以一旦几个线程处于就绪状态的话,都有机会抢到执行的机会。所以,我们的两处求系统时间的地方都是我们不希望的时间。

也就是说,我们希望结果应该是这样的,“主线程开始”-->5个子线程执行-->“主线程结束”。

 

3、成功的例子

  1. public static void main(String args[]) throws InterruptedException {
  2.      CountDownLatch latch = new CountDownLatch(5);//设置计数值
  3.      System.out.println("主线程开始");
  4.      long startTime = System.currentTimeMillis();
  5.      for(int i=0;i<5;i++) {
  6.          new Thread() {
  7.              @Override
  8.              public void run() {
  9.                  System.out.println(currentThread().getName()+"开始执行..");
  10.                  try {
  11.                      sleep(1000);
  12.                  } catch (InterruptedException e) {
  13.                      e.printStackTrace();
  14.                  }
  15.                  System.out.println(currentThread().getName()+"结束执行..");
  16.                  latch.countDown();
  17.              }
  18.          }.start();
  19.      }
  20.      latch.await();
  21.      long endTime = System.currentTimeMillis();
  22.      System.out.println("多线程运行时间:"+(endTime-startTime)+"ms");//1007ms
  23.      System.out.println("主线程结束");
  24.  }

运行结果如下

这次是结果是我们想要的。

同时,我们也看到了,5个线程,每个线程需要执行 1s (停止 1s),最终 5 个线程全部执行,只需要1s多点,而不是 5s,这就是多线程的作用。

 

  • 微信
  • 交流学习,有偿服务
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: