java使用CountDownLatch等待多线程全部执行完成

Sure!下面是我为您详细讲解如何在Java中使用CountDownLatch等待多线程全部执行完成的完整攻略。

什么是CountDownLatch

CountDownLatch是Java中的一个同步工具类,它允许一个或多个线程等待直到在其他线程完成的一组操作执行完毕。它主要是用于多线程协同,一个线程需要等待多个其它线程完成某个操作之后才能继续执行。

CountDownLatch的使用

使用CountDownLatch非常简单,主要分为两步:

1.在主线程中,初始化CountDownLatch,并设置需要等待的线程数。

2.在需要等待的线程中,在任务结束时调用CountDownLatch的countDown()方法,代表完成了一个操作。当计数器递减为0时,主线程才会继续执行。

下面是一个基本的CountDownLatch的示例代码:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        // 设置需要等待的线程数
        CountDownLatch countDownLatch = new CountDownLatch(2);

        Thread t1 = new Thread(() -> {
            // 模拟线程1需要执行的操作
            System.out.println("Thread 1 executed.");
            // 操作完成后调用countDown()方法
            countDownLatch.countDown();
        });

        Thread t2 = new Thread(() -> {
            // 模拟线程2需要执行的操作
            System.out.println("Thread 2 executed.");
            // 操作完成后调用countDown()方法
            countDownLatch.countDown();
        });

        t1.start();
        t2.start();

        // 等待两个线程执行完毕
        countDownLatch.await();

        // 所有线程执行完成后,主线程继续执行
        System.out.println("All threads executed.");
    }
}

在上面的代码中,我们初始化了一个CountDownLatch,需要等待两个线程执行完毕,然后启动了两个线程t1和t2,在线程的操作完成后调用了countDown()方法递减计数器。最后,主线程调用了await()方法,等待两个线程执行完毕。在所有线程执行完毕后,主线程才会继续执行,输出"All threads executed."。

示例说明

  • 示例一

现在我们有一个任务需要循环处理一万条数据,每条数据处理时间大约需要1秒。由于数据量比较大,我们可以使用多线程来提高处理速度。我们可以分配10个线程,每个线程处理1000条数据,并使用CountDownLatch来等待所有线程完成任务后再进行计算。

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {

    private static final int THREAD_NUMS = 10;
    private static final int DATA_NUMS = 10000;

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(THREAD_NUMS);

        // 初始化数据
        int[] data = new int[DATA_NUMS];
        for (int i = 0; i < DATA_NUMS; i++) {
            data[i] = i;
        }

        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_NUMS);

        for (int i = 0; i < THREAD_NUMS; i++) {
            final int start = i * (DATA_NUMS / THREAD_NUMS);
            final int end = (i + 1) * (DATA_NUMS / THREAD_NUMS);

            // 加入线程池
            executor.execute(() -> {
                try {
                    // 模拟处理数据
                    Thread.sleep(1000);

                    // 处理数据,这里只输出一下
                    for (int j = start; j < end; j++) {
                        System.out.println("data " + j + " is processed by " + Thread.currentThread().getName());
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 操作完成后调用countDown()方法
                    countDownLatch.countDown();
                }
            });
        }

        // 等待所有线程处理完成
        countDownLatch.await();

        // 所有线程已经处理完成,计算结果
        System.out.println("All threads executed. Calculate the sum of data.");
        long sum = 0;
        for (int i = 0; i < DATA_NUMS; i++) {
            sum += data[i];
        }
        System.out.println("The sum of data is " + sum);
        executor.shutdown();
    }
}

在上述代码中,我们初始化了一个CountDownLatch,需要等待10个线程执行完毕。首先我们初始化了一万条数据,然后创建了线程池并加入10个线程。每个线程处理1000条数据,然后调用countDown()方法递减计数器。最后,主线程调用了await()方法,等待10个线程执行完毕。在所有线程执行完毕后,主线程计算了所有数据之和并输出。

  • 示例二

假设你要实现一个游戏服务端的战斗模块,你需要对两个玩家进行匹配并进行战斗。当随机匹配到两个玩家时,需要对两个玩家进行战斗匹配,并等待战斗结束后记录战斗结果。我们可以使用CountDownLatch来控制匹配和战斗的顺序。

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(2);

        Thread matchThread = new Thread(() -> {
            // 随机匹配两个玩家,这里直接模拟随机匹配
            Random random = new Random();
            int playerId1 = random.nextInt(100);
            int playerId2 = random.nextInt(100);
            System.out.println("Match success: playerId1=" + playerId1 + ", playerId2=" + playerId2);
            // 操作完成后调用countDown()方法
            countDownLatch.countDown();
        });

        Thread battleThread = new Thread(() -> {
            try {
                // 等待匹配完成
                countDownLatch.await();

                // 匹配完成后进行战斗,这里直接模拟战斗
                System.out.println("Battle start: Player1 vs Player2");
                Thread.sleep(5000);
                System.out.println("Battle end: Player1 win.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        matchThread.start();
        battleThread.start();

        // 等待战斗结束
        battleThread.join();

        // 输出战斗结果
        System.out.println("Battle completed.");
    }
}

在上述代码中,我们初始化了一个CountDownLatch,需要等待2个线程执行完毕(匹配和战斗)。首先我们创建了随机匹配线程matchThread,并在操作完成后调用了countDown()方法递减计数器。接着我们创建了战斗线程battleThread,需要在匹配完成后进行战斗,所以在战斗线程中先调用await()方法等待匹配完成。在匹配完成后,我们模拟战斗,然后输出战斗结果。最后,主线程等待战斗线程执行完毕并输出战斗完成信息。

总结

至此,我们完成了使用CountDownLatch等待多线程全部执行完成的攻略。通过这篇文章,我们了解了CountDownLatch的基本概念和使用方法,并且也给出了两个示例代码。当你需要等待多个线程执行完毕后再继续执行后续操作时,可以考虑使用CountDownLatch来实现。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java使用CountDownLatch等待多线程全部执行完成 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • 在spring boot中使用java线程池ExecutorService的讲解

    下面就详细讲解一下“在springboot中使用java线程池ExecutorService”的完整攻略。 1. 概述 在应用程序中,我们通常需要进行一些异步的操作,例如发送邮件、短信通知等,这些操作不应该阻塞主线程的执行。Java中提供了线程池ExecutorService来帮助我们完成这些异步操作,它能够维护一定数量的线程来处理任务,避免了每次需要处理任…

    Java 2023年5月15日
    00
  • Java简单实现调用命令行并获取执行结果示例

    首先我们需要了解Java如何调用命令行来执行外部的命令。在Java中,可以通过ProcessBuilder或Runtime.getRuntime().exec()两种方式实现。 使用ProcessBuilder调用命令行 ProcessBuilder是一个Java API,它提供了一个类来启动外部进程并与其进行交互。下面是一个简单的Java程序,它使用Pro…

    Java 2023年5月23日
    00
  • Java函数式编程(六):Optional

    Java函数式编程(六):Optional Optional简介 在Java 8中,Optional成为了一个非常重要的新特性。Optional是一个容器类型,代表一个值存在或不存在。Original Java中,我们经常返回null来表示一个空值。但是在Java 8 中使用Optional来表示一个值不存在更加明确和安全。 Optional 类(java.…

    Java 2023年5月26日
    00
  • JDK8时间相关类超详细总结(含多个实例)

    JDK8时间相关类超详细总结(含多个实例) 为什么需要时间相关的类? 在程序设计中,我们经常需要使用到时间相关的操作,例如获取当前时间、将时间转换成特定格式、计算时间差等。而Java的JDK 8中提供了许多时间类的操作,可以方便地进行时间处理。 JDK8时间相关类 Instant Instant类表示时间点,它是相对于时间线上的一个点,可以精确到纳秒级别。常…

    Java 2023年5月20日
    00
  • Spring Security自定义认证逻辑实例详解

    来详细讲解一下“Spring Security自定义认证逻辑实例详解”的完整攻略。 1. 概述 Spring Security是一个功能强大的安全框架,提供了包括认证、授权、攻击防范等在内的综合安全解决方案。在Spring Security中,认证是一个非常重要的环节。本攻略旨在详细讲解Spring Security中如何自定义认证逻辑。 2. 前置条件 在…

    Java 2023年5月20日
    00
  • Spring Boot 之HelloWorld开发案例

    下面我将为大家详细讲解“SpringBoot之HelloWorld开发案例”的完整攻略。首先,我们需要了解一些SpringBoot的基础知识。 SpringBoot是一个快速开发框架,它使开发者可以快速地创建基于Spring的应用程序。SpringBoot通过自动化配置来简化Spring应用程序的初始搭建,同时可以轻松集成第三方库、插件等。 接下来,我们将详…

    Java 2023年5月15日
    00
  • java基础-数组扩容详解

    Java基础-数组扩容详解 什么是数组扩容 在Java中,数组是一个固定长度的数据结构。当我们在使用数组时,如果需要添加更多的元素,则需要声明一个新的数组并复制所有旧元素到新数组中。这个过程称为“数组扩容”。 在Java中,数组扩容是自动完成的。当我们向一个已经装满元素的数组中添加新元素时,系统会自动创建一个新的数组,并将旧元素复制到新数组中。这个过程对用户…

    Java 2023年5月26日
    00
  • 常见的几种web攻击的防范办法 web常见攻击方式

    下面就为你讲解一下常见的几种Web攻击的防范办法。 常见的Web攻击方式 以下是Web常见攻击方式: XSS攻击 CSRF攻击 SQL注入攻击 1. XSS攻击 定义 XSS攻击即跨站脚本攻击,攻击者在网页中嵌入恶意脚本,当用户访问该页面时,该恶意脚本就可以获取用户的cookie等信息,从而获取用户的敏感信息。 防范办法 对用户输入的内容进行过滤和转义,尤其…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部