for循环内线程池并发执行任务,等到子线程全部处理完任务,主线程在执行java的实现方式

这篇具有很好参考价值的文章主要介绍了for循环内线程池并发执行任务,等到子线程全部处理完任务,主线程在执行java的实现方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

for循环内线程池并发执行任务,等到子线程全部处理完任务,主线程在执行

方式一 使用 CountDownLatch

在 Java 中,您可以使用 CountDownLatch 来实现主线程等待子线程执行完成的功能。CountDownLatch 是一个同步工具类,它允许一个或多个线程等待其他线程完成操作后再继续执行。

具体来说,您可以在每个子线程中创建一个 CountDownLatch 对象,并将计数器初始化为 1。当子线程处理完任务后,调用 CountDownLatch.countDown() 方法,将计数器减 1。在主线程中,调用 CountDownLatch.await() 方法阻塞等待所有子线程的任务执行完毕,直到计数器减为 0 才继续执行后续代码。

以下是一个简单的示例代码:

ExecutorService executor = Executors.newFixedThreadPool(5); // 创建拥有 5 个线程的线程池

CountDownLatch latch = new CountDownLatch(5); // 创建计数器,初始值为 5

for (int i = 0; i < 5; i++) {
    executor.submit(() -> {
        // 子线程处理任务
        doTask();

        latch.countDown(); // 计数器减 1
    });
}

try {
    latch.await(); // 等待所有子线程的任务执行完毕
} catch (InterruptedException e) {
    // 处理中断异常
}

// 所有子线程的任务都已经执行完毕,执行主线程的代码
doSomethingElse();

请注意,在实际应用中,您还需要考虑线程安全、并发访问等问题,并在代码中正确处理异常。例如,在子线程处理任务时,可能需要使用锁或其他同步机制来保护共享资源的访问;在主线程等待子线程执行完毕时,可能需要处理 InterruptedException 异常等异常情况。

方式二 使用 ExecutorService 的 invokeAll() 方法

如果您不想使用 CountDownLatch,还有其他方法可以实现主线程等待子线程任务执行完毕的功能。以下是一些常见的方式:

使用 ExecutorService 的 invokeAll() 方法
ExecutorService 中的 invokeAll() 方法可以提交多个 Callable 或 Runnable 任务,并阻塞等待所有任务完成。该方法返回一个 Future 对象列表,可以通过遍历列表获取各个子线程处理任务后的结果。

以下是一个使用 invokeAll() 方法的示例代码

ExecutorService executor = Executors.newFixedThreadPool(5); // 创建拥有 5 个线程的线程池

List<Callable<Void>> tasks = new ArrayList<>();
for (int i = 0; i < 5; i++) {
    tasks.add(() -> {
        // 子线程处理任务
        doTask();
        return null;
    });
}

executor.invokeAll(tasks); // 等待所有子线程的任务执行完毕

// 所有子线程的任务都已经执行完毕,执行主线程的代码
doSomethingElse();

方式三 使用 CompletableFuture 的 allOf() 方法

Java 8 中引入了 CompletableFuture 类,它提供了一系列基于回调函数的异步编程方法,可以方便地实现多线程任务的并发执行和结果组合。其中,allOf() 方法可以用于等待所有 CompletableFuture 对象的计算结果。

以下是一个使用 CompletableFuture 的 allOf() 方法的示例代码:

ExecutorService executor = Executors.newFixedThreadPool(5); // 创建拥有 5 个线程的线程池

List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < 5; i++) {
    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        // 子线程处理任务
        doTask();
    }, executor);
    futures.add(future);
}

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // 等待所有子线程的任务执行完毕

// 所有子线程的任务都已经执行完毕,执行主线程的代码
doSomethingElse();

请注意,在使用以上方法时,仍然需要考虑线程安全、并发访问等问题,并在代码中正确处理异常。

方式四
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5, // corePoolSize
    5, // maximumPoolSize
    0L, TimeUnit.MILLISECONDS, // keepAliveTime, unit
    new LinkedBlockingQueue<Runnable>()); // workQueue

AtomicInteger count = new AtomicInteger(5); // 计数器,初始值为 5

for (int i = 0; i < 5; i++) {
    executor.execute(() -> {
        // 子线程处理任务
        doTask();

        count.decrementAndGet(); // 计数器减 1
    });
}

while (count.get() > 0) {
    Thread.sleep(100); // 等待一段时间,避免空转浪费 CPU 资源
}

// 所有子线程的任务都已经执行完毕,执行主线程的代码
doSomethingElse();

在上述代码中,我们创建了一个 ThreadPoolExecutor 对象,然后通过 AtomicInteger 实现了一个计数器,初始值为 5。在每个子线程执行完任务后,计数器的值减 1。在主线程中使用 while 循环检查计数器是否为 0,如果未达到目标,则阻塞等待一段时间,避免空转浪费 CPU 资源。当计数器减为 0 时,所有子线程的任务都已经执行完毕,主线程可以执行后续代码。

请注意,在使用自定义线程池时,需要考虑线程安全、并发访问等问题,并在代码中正确处理异常。例如,在子线程处理任务时,可能需要使用锁或其他同步机制来保护共享资源的访问;在主线程等待子线程执行完毕时,可能需要处理 InterruptedException 异常等异常情况。文章来源地址https://www.toymoban.com/news/detail-672504.html

到了这里,关于for循环内线程池并发执行任务,等到子线程全部处理完任务,主线程在执行java的实现方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用 Goroutine 和 Channel 来实现更复杂的并发模式,如并发任务执行、并发数据处理,如何做?

    使用 Goroutine 和 Channel 来实现更复杂的并发模式是 Go 语言的强大特性之一。 下面分别介绍如何实现并发任务执行和并发数据处理: 并发任务执行: 假设您有一些任务需要并发地执行,您可以使用 Goroutine 来同时执行这些任务,然后使用 Channel 来汇总结果。 下面是一个示例,

    2024年01月22日
    浏览(43)
  • 并发编程5:如何执行任务?

    目录 1、线程中执行任务的方式 2、Executor 框架 2.1 - 线程的执行策略 2.2 - 线程池 2.3 - Executor 的生命周期 2.4 - 延任务与周期任务 3、找出可利用的并行性-代码示例 3.1 - 单线程的 I/O 操作 3.2 - 携带任务结果的 Callable 与 Future(重要) 3.3 - 使用 Future 实现页面渲染器 3.5 - Completio

    2024年02月11日
    浏览(32)
  • qt 线程状态机实现并发自动任务

    一、状态机类 头文件 MyStateMachine.h 状态机 cpp

    2024年02月13日
    浏览(42)
  • 线程按顺序循环执行

    假设有3个线程,依次打印A、B、C,按顺序循环打印100次。 这个其实是线程通信,如果只是按顺序执行,用只有一个线程的线程池,依次提交线程任务就行,但是这里还不是每个线程只执行一次,需要循环重复打印。 这里有两种处理方式,一种是搞个全局int变量,对线程数取

    2024年02月04日
    浏览(40)
  • 多线程并发和多任务并行的小结

    一、多线程并行的一点小结 1.无论是thread::spawn还是tokio::spawn,都是创建一个线程或者任务去执行闭包的函数体。thread::spawn接受一个闭包作为参数,并返回一个 JoinHandle,其中 T 是闭包的返回类型。创建的新线程将在后台运行,并执行闭包中的代码。 2.多线程并行:其他的高级

    2024年02月10日
    浏览(44)
  • Linux--crontab命令详解--循环执行的计划任务

    循环执行任务是由cron(crond)这个系统服务来控制的。用户想要建立循环的计划任务时,使用的是crontab这个命令,为了避免安全性的问题,和at一样,我们可以限制使用crontab的账号,可以使用的配置文件有: /etc/cron.allow 将可以使用crontab的账号写入,不在这个文件中的账户则不能使用cr

    2024年02月16日
    浏览(47)
  • 深入理解高并发编程 - 线程的执行顺序

    在Java中,线程的执行顺序是由操作系统的调度机制决定的,具体顺序是不确定的,取决于多个因素,如操作系统的调度策略、线程的优先级、线程的状态转换等。因此,不能对线程的执行顺序做出可靠的假设。 以下是一个简单的Java代码示例,演示了多个线程的执行顺序是不

    2024年02月14日
    浏览(53)
  • selenium之显示等待(等到某个元素出现后再继续执行)

    本文章还请认真仔细阅读,非常简单,阅读前,你可能已经掌握,xpath 我们在爬虫的时候,总会利用time.sleep(),去等待元素的出现,但是这很容易出错,因为你不知道你的网速有多卡😂,从而导致频繁报错 我相信我的注释已经很 【言简意赅】了,你一定可以看得懂 我用了一

    2024年02月12日
    浏览(40)
  • 特别有用!Jmeter命令行执行时设置并发数和循环次数的方法

      之前写过一篇文章介绍如何在centos上部署jmeter来执行性能测试,链接如下: https://blog.csdn.net/liwenxiang629/article/details/124140833 因为大多数linux服务器都是没有GUI界面的,这就需要我们通过命令行的方式来运行jmeter脚本,具体如下: jmeter -n -t /opt/jmeter/script/test.jmx -l test2.jtl 参数

    2023年04月10日
    浏览(37)
  • 基于Mongodb分布式锁简单实现,解决定时任务并发执行问题

    我们日常开发过程,会有一些定时任务的代码来统计一些系统运行数据,但是我们应用有需要部署多个实例,传统的通过配置文件来控制定时任务是否启动又太过繁琐,而且还经常出错,导致一些异常数据的产生 网上有很多分布式锁的实现方案,基于redis、zk、等有很多,但

    2023年04月18日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包