1.使用ExecutorServiceCountDownLatch的方法示例

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

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

import java.util.concurrent.*;  

public class ThreadPoolExample {  

    public static void main(String[] args) throws InterruptedException {
// 创建一个包含固定数量线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(4); // 定义任务数量
int taskCount = 10; // 使用CountDownLatch来等待所有任务完成
final CountDownLatch latch = new CountDownLatch(taskCount); // 提交任务到线程池
for (int i = 0; i < taskCount; i++) {
int taskId = i;
executorService.submit(() -> {
// 模拟任务执行
try {
Thread.sleep(1000); // 假设每个任务需要1秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("任务 " + taskId + " 完成");
// 每完成一个任务,计数减一
latch.countDown();
});
} // 等待所有任务完成
System.out.println("等待所有任务完成...");
latch.await(); // 阻塞当前线程,直到latch的计数达到零
System.out.println("所有任务完成!"); // 关闭线程池
executorService.shutdown(); // 可选:等待线程池中的线程都执行完毕
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
// 线程池没有在规定时间内关闭,则强制关闭
executorService.shutdownNow();
}
} catch (InterruptedException e) {
// 当前线程在等待过程中被中断
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

在这个示例中,我使用了传统的匿名内部类来创建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. C语言:将文件中所得到的单词表保存到一个顺序表中--使用动态分配数组。

    在很多时候我们想要在程序中存储想要的信息,但是又不知道该信息的大小或者说不知道需要多长的数组来存放.动态分配空间这个很好的解决了这个问题,动态分配不仅只可以用在链表中分配节点空间,其实更多时候用来分配 ...

  2. .NET 采用开源软件OpenOffice 实现文档转码服务(word ppt excel)转PDF

    前言 前几年做了个项目,里面有个需求,需要在浏览器中在线浏览word excel ppt  pdf等文档. 最近又开始研究并记录下来 当时方案: 因为浏览器中阅读文档暂时只能通过pdf方式读取,所以就 ...

  3. ETSI GS MEC 013,UE 位置 API

    目录 文章目录 目录 版本 功能理解 Relation with OMA APIs Relation with OMA API for Zonal Presence Relation with OMA ...

  4. Inno Setup Dependency Installer 安装包 运行环境安装

    Download and install any dependency such as .NET, Visual C++ or SQL Server during your application's ...

  5. Abp vNext框架 基础知识 依赖注入

    依赖注入 ABP的依赖注入系统是基于Microsoft的依赖注入扩展库(Microsoft.Extensions.DependencyInjection nuget包)开发的.因此,它的文档在ABP中 ...

  6. OpenVSCode云端IDE加入Rainbond一体化开发体系

    OpenVSCode 是一款基于Web 界面的在线IDE 代码编辑器,只需要PC端存在浏览器即可使用,更轻量,高效,简洁,其基础功能完全继承了微软出品的 VS Code ,可以通过安装扩展的方式继续加 ...

  7. 一种基于E3处理器平台的NAS完整方案(从电脑组装到网站部署)

    一种基于E3处理器平台的NAS完整方案(从电脑组装到网站部署) 本文将简要简要介绍本人自建NAS的完整配置,截至发文此NAS已经连续良好运行一年,应当说具有良好的稳定性. 本文所述配置包含洋垃圾成分, ...

  8. ES5的继承语法

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  9. 使用Jsoup和htmlunit爬取动态网页

    在对http://zkgg.tjtalents.com.cn/newzxxx.jsp这个网页爬取内容时,如果只使用Jsoup进行解析的话,起内部的a href标签内容无法获取到. 但是实际上通过 Do ...

  10. 剑指Offer-49.把字符串转换成整数(C++/Java)

    题目: 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 数值为0或者字符串不是一个合法的数值则返回0 输入描述: 输入一个字符串,包括数字字母符号,可以为空 输出描述: 如果是合法的 ...