Java并发之CountDownLatch

简介: Java并发之CountDownLatch

CountDownLatch

CountDownLatch是java多线程包concurrent里的一个常见工具类,通过使用它可以借助线程能力极大提升处理响应速度,且实现方式非常优雅。

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

核心api

CountDownLatch(int count) //实例化一个倒计数器,count指定计数个数
countDown() // 计数减一
await() //等待,当计数减到0时,所有线程并行执行

案例

在一个程序中需要调用两个服务的接口后才能执行下一步,那么我们需要判断这连个接口是否调用成功,并且这两个接口需要较长的时间,那么我们就可以使CountDownLatch来完成

抽象类

/**
 * @Description: 抽象类,统一
 * @author BushRo
 * @date 2019-07-16
 * @version 1.0
 *
 */
public abstract class Center implements Runnable {
  private CountDownLatch countDown;   // 计数器
  private String server;          // 服务名称
  private boolean ok;           // 服务是否调用成功标识
  public Center(CountDownLatch countDown, String server) {
    this.countDown = countDown;
    this.server = server;
    this.ok = false;
  }
  @Override
  public void run() {
    try {
      work();
      ok = true;
    } catch (Exception e) {
      e.printStackTrace();
      ok = false;
    } finally {
      if (countDown != null) {
        countDown.countDown();
      }
    }
  }
  /**
   * @Description: 抽象方法
   * @author BushRo
   * @date 2019-07-16
   * @version 1.0
   *
   */
  public abstract void work();
  public CountDownLatch getCountDown() {
    return countDown;
  }
  public void setCountDown(CountDownLatch countDown) {
    this.countDown = countDown;
  }
  public String getServer() {
    return server;
  }
  public void setServer(String server) {
    this.server = server;
  }
  public boolean isOk() {
    return ok;
  }
  public void setOk(boolean ok) {
    this.ok = ok;
  }
}

服务A

/**
 * @Description: 服务A工作
 * @author BushRo
 * @date 2019-07-16
 * @version 1.0
 *
 */
public class ServerA extends Center {
  public ServerA(CountDownLatch countDown) {
    super(countDown, "服务A");
  }
  @Override
  public void work() {
    System.out.println("正在获取 [" + this.getServer() + "]接口数据...");
    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("获取 [" + this.getServer() + "] 数据完毕");
  }
}

服务B

/**
 * @Description: 服务B工作
 * @author BushRo
 * @date 2019-07-16
 * @version 1.0
 *
 */
public class ServerB extends Center {
  public ServerB(CountDownLatch countDown) {
    super(countDown, "服务B");
  }
  @Override
  public void work() {
    System.out.println("正在获取 [" + this.getServer() + "]接口数据...");
    try {
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("获取 [" + this.getServer() + "] 数据完毕");
  }
}

调用

在使用countDown.await();方法的时候好设置一下时间,否则有一个线程阻塞了,就会导致程序阻塞无法返回值了

public class CheckStartUp {
  private static List<Center> serverList;
  private static CountDownLatch countDown;
  public CheckStartUp() {
  }
  public static boolean checkAllStations() throws Exception {
    // 初始化2个服务
    countDown = new CountDownLatch(2);
    // 把所有站点添加进list
    serverList = new ArrayList<>();
    serverList.add(new ServerA(countDown));
    serverList.add(new ServerB(countDown));
    // 使用线程池
    Executor executor = Executors.newFixedThreadPool(serverList.size());
    for (Center center : serverList) {
      //分别执行三个线程
      executor.execute(center);
    }
    // 等待线程执行完毕
    //countDown.await();
    /**
     * 在等待的时候最好设置一下时间,否则有一个线程阻塞了,
     * 就会导致程序阻塞无法返回值了
     */
    countDown.await(20,TimeUnit.SECONDS);
    for (Center center : serverList) {
      if (!center.isOk()) {
        return false;
      }
    }
    return true;
  }
  public static void main(String[] args) throws Exception {
    long starttime = System.currentTimeMillis();
    boolean result = CheckStartUp.checkAllStations();
    System.out.println("服务的调用结果为:" + result);
    long endtime = System.currentTimeMillis();
    System.out.println("用时:"
        + (endtime - starttime) + "毫秒!");
  }
}

运行效果,这样我们就极大的节约了时间

20190716223821860.png

相关文章
|
2月前
|
Java 大数据 Go
从混沌到秩序:Java共享内存模型如何通过显式约束驯服并发?
并发编程旨在混乱中建立秩序。本文对比Java共享内存模型与Golang消息传递模型,剖析显式同步与隐式因果的哲学差异,揭示happens-before等机制如何保障内存可见性与数据一致性,展现两大范式的深层分野。(238字)
90 4
|
2月前
|
缓存 安全 Java
如何理解Java中的并发?
Java并发指多任务交替执行,提升资源利用率与响应速度。通过线程实现,涉及线程安全、可见性、原子性等问题,需用synchronized、volatile、线程池及并发工具类解决,是高并发系统开发的关键基础。(238字)
241 5
|
3月前
|
Java 开发者
Java并发编程:CountDownLatch实战解析
Java并发编程:CountDownLatch实战解析
466 100
|
5月前
|
SQL 缓存 安全
深度理解 Java 内存模型:从并发基石到实践应用
本文深入解析 Java 内存模型(JMM),涵盖其在并发编程中的核心作用与实践应用。内容包括 JMM 解决的可见性、原子性和有序性问题,线程与内存的交互机制,volatile、synchronized 和 happens-before 等关键机制的使用,以及在单例模式、线程通信等场景中的实战案例。同时,还介绍了常见并发 Bug 的排查与解决方案,帮助开发者写出高效、线程安全的 Java 程序。
268 0
|
5月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
375 83
|
5月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
347 83
|
6月前
|
Java 物联网 数据处理
Java Solon v3.2.0 史上最强性能优化版本发布 并发能力提升 700% 内存占用节省 50%
Java Solon v3.2.0 是一款性能卓越的后端开发框架,新版本并发性能提升700%,内存占用节省50%。本文将从核心特性(如事件驱动模型与内存优化)、技术方案示例(Web应用搭建与数据库集成)到实际应用案例(电商平台与物联网平台)全面解析其优势与使用方法。通过简单代码示例和真实场景展示,帮助开发者快速掌握并应用于项目中,大幅提升系统性能与资源利用率。
203 6
Java Solon v3.2.0 史上最强性能优化版本发布 并发能力提升 700% 内存占用节省 50%
|
7月前
|
缓存 安全 Java
【高薪程序员必看】万字长文拆解Java并发编程!(3-1):并发共享问题的解决与分析
活锁:多个线程相互影响对方退出同步代码块的条件而导致线程一直运行的情况。例如,线程1的退出条件是count=5,而线程2和线程3在其代码块中不断地是count进行自增自减的操作,导致线程1永远运行。内存一致性问题:由于JIT即时编译器对缓存的优化和指令重排等造成的内存可见性和有序性问题,可以通过synchronized,volatile,并发集合类等机制来解决。这里的线程安全是指,多个线程调用它们同一个实例的方法时,是线程安全的,但仅仅能保证当前调用的方法是线程安全的,不同方法之间是线程不安全的。
139 0
|
7月前
|
Java 程序员
【高薪程序员必看】万字长文拆解Java并发编程!(3-2):并发共享问题的解决与分析
wait方法和notify方法都是Object类的方法:让当前获取锁的线程进入waiting状态,并进入waitlist队列:让当前获取锁的线程进入waiting状态,并进入waitlist队列,等待n秒后自动唤醒:在waitlist队列中挑一个线程唤醒:唤醒所有在waitlist队列中的线程它们都是之间协作的手段,只有拥有对象锁的线程才能调用这些方法,否则会出现IllegalMonitorStateException异常park方法和unpark方法是LockSupport类中的方法。
156 0