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日

相关文章

  • java中全排列的生成算法汇总

    Java中全排列的生成算法汇总 一、什么是全排列 全排列,是指将一组数按一定顺序进行排列,称为这组数的全排列。 如有三个数a、b、c,则它们的全排列有:a、b、c、ab、ac、ba、bc、ca、cb、abc、acb、bac、bca、cab、cba 共6个。 二、生成全排列的算法 在Java中,生成全排列的算法有以下几种: 1.递归算法 这种算法实现简单,思路…

    Java 2023年5月19日
    00
  • 什么是运行时异常?

    运行时异常指在程序运行过程中,由于程序逻辑错误或者环境条件异常等原因,导致程序抛出的异常。与编译时异常不同的是,运行时异常不需要在代码中显示地声明或捕获,而是在程序运行时动态地抛出和处理。 常见的运行时异常包括:空指针异常(NullPointerException)、数组下标越界异常(ArrayIndexOutOfBoundsException)、类型转换异…

    Java 2023年4月27日
    00
  • Java中IO流解析及代码实例详解

    Java中IO流解析及代码实例详解 什么是Java中的IO流? Java中的IO流是在文件系统、网络等输入/输出流通道中进行数据传输的方式,Java中的IO流提供了对数据的字节和字符等级别的访问,包括对文件系统和网络的字节和字符输入/输出流通道的访问。 Java中的IO流分为字节流和字符流两种,字节流与底层操作系统直接交互,因此具有较高的性能,而字符流通过对…

    Java 2023年5月27日
    00
  • Spring依赖注入(DI)两种方式的示例详解

    下面我将为你详细讲解“Spring依赖注入(DI)两种方式的示例详解”的完整攻略。 1. 什么是Spring依赖注入(DI) Spring依赖注入(Dependency Injection,简称 DI)是指一个对象依赖于另一个对象。通俗一些的说法就是对象 A 需要对象 B 的协助完成某些功能,但是对象 A 并不负责创建对象 B,而是由 Spring 容器来创…

    Java 2023年5月20日
    00
  • CAS操作的实现原理是什么?

    CAS(Compare And Swap)是一种并发控制机制,用于保证多线程并发修改时的数据一致性。它主要包括三个操作数:内存地址V、旧的预期值A和新的值B。当且仅当内存地址V的值和预期值A相同时,才把新的值B赋值给内存地址V,否则就什么都不做。下面就来详细讲解一下CAS操作的实现原理: CAS操作的实现原理 在计算机能够完成CAS操作的原理中,有两个非常重…

    Java 2023年5月10日
    00
  • SpringBoot后端接收数组对象的实现

    下面就是”SpringBoot后端接收数组对象的实现”的完整攻略: 1. 创建后端接口接收数组对象 在SpringBoot中创建后端接收数组对象的接口时,可以使用@RequestParam注解将前端传过来的数组转化为Java中的List对象,示例如下: @PostMapping("/api/saveData") public void s…

    Java 2023年5月20日
    00
  • Java 使用IO流实现大文件的分割与合并实例详解

    Java 使用IO流实现大文件的分割与合并实例详解 前言 在现代应用程序中,经常需要处理非常大的文件。处理大文件的一种常见方法是将它们分成更小的文件,这有助于减少I/O操作的时间和资源消耗。在Java中,可以使用IO流来实现大文件的分割与合并。 分割文件 读取源文件 首先,我们需要通过使用Java IO API中的FileInputStream读取要分割的源…

    Java 2023年5月20日
    00
  • @RequestBody时第二个字母大写,映射不到的解决

    使用Spring MVC时,通常可以使用@RequestBody注解来接收HTTP请求的JSON数据,并将请求体转换为Java对象。但在实际使用过程中,有时会遇到使用@RequestBody时第二个字母大写时,映射不到的问题。这是因为Spring MVC默认情况下使用的是Jackson库来进行JSON转换,而Jackson库的命名策略默认是采用小写字母和下划…

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