1.使用ExecutorServiceCountDownLatch的方法示例

在Java中,当我们使用线程池(如ExecutorService)来执行异步任务时,常常需要知道所有任务是否都已经完成。ExecutorService接口提供了几种方式来处理这种情况,但最常用的是shutdown()awaitTermination()方法的组合,或者使用FutureCompletionService。这里我将提供一个使用ExecutorServiceCountDownLatch的示例,因为CountDownLatch提供了一种直观的方式来等待一组线程完成。

首先,我们定义几个任务,然后使用ExecutorService来异步执行它们,并使用CountDownLatch来等待所有任务完成。

  1. import java.util.concurrent.*;
  2. public class ThreadPoolExample {
  3. public static void main(String[] args) throws InterruptedException {
  4. // 创建一个包含固定数量线程的线程池
  5. ExecutorService executorService = Executors.newFixedThreadPool(4);
  6. // 定义任务数量
  7. int taskCount = 10;
  8. // 使用CountDownLatch来等待所有任务完成
  9. final CountDownLatch latch = new CountDownLatch(taskCount);
  10. // 提交任务到线程池
  11. for (int i = 0; i < taskCount; i++) {
  12. int taskId = i;
  13. executorService.submit(() -> {
  14. // 模拟任务执行
  15. try {
  16. Thread.sleep(1000); // 假设每个任务需要1秒
  17. } catch (InterruptedException e) {
  18. Thread.currentThread().interrupt();
  19. }
  20. System.out.println("任务 " + taskId + " 完成");
  21. // 每完成一个任务,计数减一
  22. latch.countDown();
  23. });
  24. }
  25. // 等待所有任务完成
  26. System.out.println("等待所有任务完成...");
  27. latch.await(); // 阻塞当前线程,直到latch的计数达到零
  28. System.out.println("所有任务完成!");
  29. // 关闭线程池
  30. executorService.shutdown();
  31. // 可选:等待线程池中的线程都执行完毕
  32. try {
  33. if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
  34. // 线程池没有在规定时间内关闭,则强制关闭
  35. executorService.shutdownNow();
  36. }
  37. } catch (InterruptedException e) {
  38. // 当前线程在等待过程中被中断
  39. executorService.shutdownNow();
  40. Thread.currentThread().interrupt();
  41. }
  42. }
  43. }

在这个例子中,我们首先创建了一个固定大小的线程池(这里使用4个线程)。然后,我们定义了一个CountDownLatch,其计数被初始化为任务的数量(这里为10)。对于每个任务,我们都向线程池提交了一个Runnable,其中包含了任务的执行逻辑和latch.countDown()调用,以确保每次任务完成时都会减少CountDownLatch的计数。

主线程通过调用latch.await()来等待,直到所有任务都调用了countDown()(即计数达到零),然后才能继续执行。这确保了主线程会等待所有任务完成后再继续。

最后,我们关闭了线程池,并通过调用awaitTermination()来可选地等待线程池中的所有线程都执行完毕。如果线程池没有在指定时间内关闭,则调用shutdownNow()来尝试立即停止所有正在执行的任务。

这个示例提供了处理异步任务并等待它们完成的一种有效方式,适用于需要等待所有任务完成再继续的场景。

2.使用ExecutorServiceinvokeAll方法和Future列表的方法示例

除了使用CountDownLatch之外,还有其他方法可以判断线程池中的所有任务是否执行完成。以下是一个使用ExecutorServiceinvokeAll方法和Future列表的示例,这种方法适用于我们有一组已知的任务(Callable)需要并行执行,并且我们需要等待所有任务完成并获取它们的结果。

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.concurrent.*;
  4. public class ThreadPoolFutureExample {
  5. public static void main(String[] args) throws InterruptedException, ExecutionException {
  6. // 创建一个包含固定数量线程的线程池
  7. ExecutorService executorService = Executors.newFixedThreadPool(4);
  8. // 创建一个Callable任务列表
  9. List<Callable<String>> tasks = new ArrayList<>();
  10. for (int i = 0; i < 10; i++) {
  11. final int taskId = i;
  12. tasks.add(() -> {
  13. // 模拟任务执行
  14. Thread.sleep(1000); // 假设每个任务需要1秒
  15. return "任务 " + taskId + " 完成";
  16. });
  17. }
  18. // 使用invokeAll提交所有任务,这将返回一个Future列表
  19. List<Future<String>> futures = executorService.invokeAll(tasks);
  20. // 遍历Future列表,获取每个任务的结果
  21. for (Future<String> future : futures) {
  22. // get()会阻塞,直到对应的任务完成
  23. System.out.println(future.get());
  24. }
  25. // 关闭线程池
  26. executorService.shutdown();
  27. // 可选:等待线程池中的线程都执行完毕
  28. try {
  29. if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
  30. // 线程池没有在规定时间内关闭,则强制关闭
  31. executorService.shutdownNow();
  32. }
  33. } catch (InterruptedException e) {
  34. // 当前线程在等待过程中被中断
  35. executorService.shutdownNow();
  36. Thread.currentThread().interrupt();
  37. }
  38. }
  39. }
  40. // 注意:这里使用了Lambda表达式和方法引用来简化Callable的创建
  41. // 实际使用中,你可能需要实现Callable接口或使用匿名内部类

在这个例子中,我们创建了一个ExecutorService和一个Callable任务列表。每个Callable任务都会返回一个字符串,表示任务完成的信息。我们使用invokeAll方法提交了所有任务,并立即获得了一个Future列表,每个Future都代表了一个任务的执行结果。

然后,我们遍历这个Future列表,并对每个Future调用get()方法。get()方法会阻塞当前线程,直到对应的任务完成并返回结果。这样,我们就能确保在继续执行之前,所有任务都已经完成。

最后,我们关闭了线程池,并等待所有线程都执行完毕(或超时后强制关闭)。

请注意,虽然这个示例使用了CallableFuture,但它并没有直接提供一个“是否所有任务都已完成”的布尔值。然而,通过遍历Future列表并调用get(),我们实际上已经达到了等待所有任务完成的效果。如果我们只需要知道是否所有任务都已开始执行(而不是等待它们完成),那么我们可能需要采用不同的策略,比如使用execute方法结合其他同步机制(如CountDownLatch)。

3.使用ExecutorService来异步执行多个Callable任务方法示例

以下是一个详细完整的代码示例,该示例使用了ExecutorService来异步执行多个Callable任务,并通过遍历Future列表来等待所有任务完成并获取它们的结果。

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.concurrent.*;
  4. public class ThreadPoolFutureCompleteExample {
  5. public static void main(String[] args) {
  6. // 创建一个包含固定数量线程的线程池
  7. ExecutorService executorService = Executors.newFixedThreadPool(4);
  8. // 创建一个Callable任务列表
  9. List<Callable<String>> tasks = new ArrayList<>();
  10. for (int i = 0; i < 10; i++) {
  11. final int taskId = i;
  12. tasks.add(new Callable<String>() {
  13. @Override
  14. public String call() throws Exception {
  15. // 模拟任务执行
  16. TimeUnit.SECONDS.sleep(1); // 假设每个任务需要1秒
  17. return "任务 " + taskId + " 完成";
  18. }
  19. });
  20. // 或者使用Lambda表达式(如果你使用的是Java 8或更高版本)
  21. // tasks.add(() -> {
  22. // TimeUnit.SECONDS.sleep(1);
  23. // return "任务 " + taskId + " 完成";
  24. // });
  25. }
  26. try {
  27. // 使用invokeAll提交所有任务,这将返回一个Future列表
  28. List<Future<String>> futures = executorService.invokeAll(tasks);
  29. // 遍历Future列表,获取每个任务的结果
  30. for (Future<String> future : futures) {
  31. // get()会阻塞,直到对应的任务完成
  32. System.out.println(future.get());
  33. }
  34. // 关闭线程池
  35. executorService.shutdown();
  36. // 等待线程池中的所有线程都执行完毕(可选)
  37. // 注意:由于我们已经调用了invokeAll并等待了所有Future的完成,这一步通常是多余的
  38. // 但为了完整性,我还是展示了如何等待线程池关闭
  39. boolean terminated = executorService.awaitTermination(60, TimeUnit.SECONDS);
  40. if (!terminated) {
  41. // 如果线程池没有在规定时间内关闭,则强制关闭
  42. System.err.println("线程池没有在规定时间内关闭,尝试强制关闭...");
  43. executorService.shutdownNow();
  44. // 注意:shutdownNow()不保证已经提交的任务会被取消
  45. // 它会尝试停止正在执行的任务,但已经开始执行的任务可能无法被中断
  46. }
  47. } catch (InterruptedException | ExecutionException e) {
  48. // 处理异常
  49. e.printStackTrace();
  50. // 如果当前线程在等待过程中被中断,尝试关闭线程池
  51. if (!executorService.isShutdown()) {
  52. executorService.shutdownNow();
  53. }
  54. // 根据需要,可能还需要重新设置中断状态
  55. Thread.currentThread().interrupt();
  56. }
  57. }
  58. }

在这个示例中,我使用了传统的匿名内部类来创建Callable任务(同时也提供了Lambda表达式的注释),以便与各种Java版本兼容。然而,如果我们正在使用Java 8或更高版本,我强烈推荐我们使用Lambda表达式来简化代码。

请注意,invokeAll方法会阻塞调用它的线程,直到所有任务都完成,或者直到等待超时(如果我们提供了超时时间)。但是,在这个示例中,我们没有为invokeAll提供超时时间,因此它会一直等待,直到所有任务都完成。

另外,请注意,在catch块中,如果捕获到InterruptedException,我们检查了线程池是否已经被关闭(使用isShutdown方法)。如果没有,我们调用shutdownNow方法来尝试关闭线程池并停止正在执行的任务。然而,需要注意的是,shutdownNow方法并不保证能够停止所有已经开始执行的任务,因为某些任务可能无法被中断。

最后,如果在捕获到InterruptedException后,我们确定当前线程需要被重新中断(比如,我们在一个循环中等待某个条件,而中断是用来退出循环的),那么我们应该调用Thread.currentThread().interrupt()来重新设置中断状态。在这个示例中,我们没有这样做,因为main方法不需要重新中断。但是,在更复杂的场景中,这可能是必要的。

Java异步判断线程池所有任务是否执行完成的方法的更多相关文章

  1. Java如何判断线程池所有任务是否执行完毕

    import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Tes ...

  2. Java异步、线程池解决方案

    一.ThreadPoolExecutor------线程池 private static final ThreadPoolExecutor threadPoolExecutor = new Threa ...

  3. java并发包&线程池原理分析&锁的深度化

          java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的, ...

  4. JAVA多线程(三) 线程池和锁的深度化

    github演示代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-servic ...

  5. Java 并发编程 | 线程池详解

    原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...

  6. Java并发包线程池之Executors、ExecutorCompletionService工具类

    前言 前面介绍了Java并发包提供的三种线程池,它们用处各不相同,接下来介绍一些工具类,对这三种线程池的使用. Executors Executors是JDK1.5就开始存在是一个线程池工具类,它定义 ...

  7. Java并发包线程池之ScheduledThreadPoolExecutor

    前言 它是一种可以安排在给定的延迟之后执行一次或周期性执行任务的ThreadPoolExecutor.因为它继承了ThreadPoolExecutor, 当然也具有处理普通Runnable.Calla ...

  8. Java多线程与线程池技术

    一.序言 Java多线程编程线程池被广泛使用,甚至成为了标配. 线程池本质是池化技术的应用,和连接池类似,创建连接与关闭连接属于耗时操作,创建线程与销毁线程也属于重操作,为了提高效率,先提前创建好一批 ...

  9. Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

    介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异步任务你还只是如下new T ...

  10. Java四种线程池

    Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor 时间:20 ...

随机推荐

  1. ctf_web

    ctfshow web13 访问题目链接 一看是一道文件上传题,上传文件进行测试 上传php会显示 error suffix 因此推测会检测格式 当文件字数超出一定字数时,显示 error file ...

  2. 环境声音分类的深度 CNN 模型

    具体的软硬件实现点击 http://mcu-ai.com/ MCU-AI技术网页_MCU-AI 声音事件的分类精度与特征提取有很强的关系.本文将深度特征用于环境声音分类(ESC)问题.深层特征是通过使 ...

  3. 使用 TortoiseGit 时,报 Access denied 错误

    当输入正确的密码时,总是报如下错误: 解决方法: 然后弹出如下对话框: 然后编辑本地配置文件: 然后将红色框的SSH配置改为绿色框的 HTTP配置,点击保存,确定. 然后再进行拉取源码,先输入用户名, ...

  4. Vue cli路由

    上面是将Forecast组件作为了Home的子组件使用,现在我们将其作为一个路由组件使用. 在router/index.js路由系统注册路由: { path: '/forecast', name: ' ...

  5. go encoding/json 替代者

    https://github.com/json-iterator/go 可以替代官方包encoding/json 提升json编码和解码效率

  6. 很多人讲不明白HTTPS,但是我能

    很多人讲不明白HTTPS,但是我能 今天我们用问答的形式,来彻底弄明白HTTPS的过程 下面的问题都是 小明和小丽两个人通信为例 可以把小明想象成服务端,小丽想象成客户端 1. https是做什么用的 ...

  7. SMOGN算法Python实现:解决回归分析中的数据不平衡

      本文介绍基于Python语言中的smogn包,读取.csv格式的Excel表格文件,实现SMOGN算法,对机器学习.深度学习回归中,训练数据集不平衡的情况加以解决的具体方法.   在不平衡回归问题 ...

  8. css 跑马灯

    html: <view class="in_scro"> <view class="in_scrview">恭喜139******1用户 ...

  9. 通过JS来触发<a>链接来实现图片下载

    function downloadImg(){ var url = '实际情况的图片URL'; // 获取图片地址 var a = document.createElement('a'); // 创建 ...

  10. CRP关键渲染路径笔记

    关键渲染路径CRP笔记 关键渲染路径(Critical Render Process)是浏览器将HTML.CSS和JavaScript代码转换为屏幕上像素的步骤序列,它包含了DOM(Document ...