线程执行者(六)运行多个任务并处理所有结果

news/2025/2/8 22:13:34

运行多个任务并处理所有结果

执行者框架允许你在不用担心线程创建和执行的情况下,并发的执行任务。它还提供了Future类,这个类可以用来控制任务的状态,也可以用来获得执行者执行任务的结果。

如果你想要等待一个任务完成,你可以使用以下两种方法:

  • 如果任务执行完成,Future接口的isDone()方法将返回true。
  • ThreadPoolExecutor类的awaitTermination()方法使线程进入睡眠,直到每一个任务调用shutdown()方法之后完成执行。

这两种方法都有一些缺点。第一个方法,你只能控制一个任务的完成。第二个方法,你必须等待一个线程来关闭执行者,否则这个方法的调用立即返回。

ThreadPoolExecutor类提供一个方法,允许你提交任务列表给执行者,并且在这个列表上等待所有任务的完成。在这个指南中,你将学习如何使用这个特性,实现一个示例,执行3个任务,并且当它们完成时将结果打印出来。

准备工作…

这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

如何做…

按以下步骤来实现的这个例子:

1.创建Result类,存储这个示例中并发任务产生的结果。


1 public class Result {

2.声明两个私有属性。一个String属性,名为name,另一个int属性,名为value。


1 private String name;
2 private int value;

3.实现相应的get()和set()方法,用来设置和获取name和value属性的值。


01 public String getName() {
02 return name;
03}
04 public void setName(String name) {
05 this.name = name;
06}
07 public int getValue() {
08 
09 return value;
10}
11 public void setValue(int value) {
12 this.value = value;
13}

4.创建Task类,实现Callable接口,参数化为Result类型。


1 public class Task implements Callable<Result> {

5.声明一个私有String属性,名为name。


1 private String name;

6.实现Task类构造器,初始化这个属性。


1 public Task(String name) {
2 this.name=name;
3}

7.实现这个类的call()方法,在本例中,它将返回一个Result对象。


1@Override
2 public Result call() throws Exception {

8.首先,写入一个信息到控制台,表明任务开始。


1 System.out.printf("%s: Staring\n",this.name);

9.然后,等待一个随机时间。


1 try {
2 long duration=(long)(Math.random()*10);
3 System.out.printf("%s: Waiting %d seconds for results.\n",this.name,duration);
4TimeUnit.SECONDS.sleep(duration);
5 } catch (InterruptedException e) {
6e.printStackTrace();
7}

10.在Result对象中返回一个计算5个随机数的总和的int值。


1 int value=0;
2 for (int i=0; i<5; i++){
3 value+=(int)(Math.random()*100);
4}

11.创建Result对象,用任务的名称和前面操作结果来初始化它。


1 Result result=new Result();
2 result.setName(this.name);
3result.setValue(value);

12.写入一个信息到控制台,表明任务已经完成。


1 System.out.println(this.name+": Ends");

13.返回Result对象。


1 return result;
2}

14.最后,实现这个示例的主类,创建Main类,实现main()方法。


1 public class Main {
2 public static void main(String[] args) {

15.使用Executors类的newCachedThreadPool()方法,创建ThreadPoolExecutor对象。


1ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool();

16.创建Task对象列表。创建3个Task对象并且用这个列表来存储。


1 List<Task> taskList=new ArrayList<>();
2 for (int i=0; i<3; i++){
3 Task task=new Task(i);
4taskList.add(task);
5}

17.创建Future对象列表,参数化为Result类型。


1 List<Future<Result>>resultList=null;

18.调用ThreadPoolExecutor类的invokeAll()方法。这个类将会返回之前创建的Future对象列表。


1 try {
2resultList=executor.invokeAll(taskList);
3 } catch (InterruptedException e) {
4e.printStackTrace();
5}

19.使用shutdown()方法结束执行者。


1executor.shutdown();

20.写入处理Future对象列表任务的结果。


01 System.out.println("Main: Printing the results");
02 for (int i=0; i<resultList.size(); i++){
03Future<Result> future=resultList.get(i);
04 try {
05Result result=future.get();
06 System.out.println(result.getName()+": "+result.
07getValue());
08 } catch (InterruptedException | ExecutionException e) {
09e.printStackTrace();
10}
11}

它是如何工作的…

在这个指南中,你已经学习了如何提交任务列表到执行者和使用invokeAll()方法等待它们的完成。这个方法接收Callable对象列表和返回 Future对象列表。这个列表将会有列表中每个任务的一个Future对象。Future对象列表的第一个对象是Callable对象列表控制的第一个任务,以此类推。

第一点要考虑的是,在存储结果对象的列表中声明的Future接口参数化的数据类型必须与使用的Callable对象的参数化相兼容。在本例中,你已经使用相同数据类型:Result类型。

另一个重要的一点就是关于invokeAll()方法,你会使用Future对象获取任务的结果。当所有的任务完成时,这个方法结束,如果你调用返回的Future对象的isDone()方法,所有调用都将返回true值。

不止这些…

ExecutorService类提供其他版本的invokeAll()方法:

  • invokeAll(Collection<? extends Callable<T>> tasks, long timeout,TimeUnit unit):此方法执行所有任务,当它们全部完成且未超时,返回它们的执行结果。TimeUnit类是个枚举类,有如下常量:DAYS,HOURS,MICROSECONDS, MILLISECONDS, MINUTES,,NANOSECONDS 和SECONDS。

参见

  • 在第4章,线程执行者中的执行者执行返回结果的任务指南
  • 在第4章,线程执行者中的运行多个任务并处理第一个结果指南

http://www.niftyadmin.cn/n/4585928.html

相关文章

Java数据结构与算法(4) 冒泡排序

###前言 最近编程状态很自由&#xff0c;我挺喜欢这种感觉。不过还是要给自己制定一个计划&#xff0c;每天学习一小节《Java数据结构与算法》和看一小节刘宇波老师的《数据结构与算法》视频&#xff0c;还有就是学习Spring Boot项目课程。然后每天晚上的时候&#xff0c;写一篇…

Vitalik对“信任模型”的思考

Vitalik对“信任模型”的思考 许多区块链应用程序最有价值的属性之一是去信任&#xff1a;应用程序能够以预期的方式继续操作&#xff0c;而不需要依赖特定的参与者以特定的方式进行操作。 即使他们的利益可能会改变&#xff0c;并推动他们在未来以一些不同的意想不到的方式行…

JAVA DES加密和解密工具类

2019独角兽企业重金招聘Python工程师标准>>> package com.afreon.util;import java.io.IOException; import java.security.SecureRandom;import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.…

Web3 网络效应:五种心智模型

Web3 网络效应&#xff1a;五种心智模型 在过去的十年里&#xff0c;网络效应推动了Web2平台的崛起&#xff0c;也奠定了其主导地位&#xff0c;同时激发了建设者和投资者的想象力。一些人认为网络效应在Web3中会更加强大&#xff0c;而另一些人则认为Web3会扼杀网络效应。 在…

注意padding-top 百分比定义基于父元素宽度的百分比上内边距!!是基于宽度

定义和用法 padding-top 属性设置元素的上内边距&#xff08;空间&#xff09;。 说明 该属性设置元素上内边距的宽度。行内非替换元素上设置的上内边距不会影响行高计算&#xff0c;因此&#xff0c;如果一个元素既有内边距又有背景&#xff0c;从视觉上看可能延伸到其他行&am…

卡牌NFT游戏的角逐:Shiryo能否脱颖而出?

卡牌NFT游戏的角逐&#xff1a;Shiryo能否脱颖而出&#xff1f; Shiryo想要创造一款NFT交易卡牌游戏&#xff0c;让玩家能够享受其中&#xff0c;而不是去玩游戏来赚钱。 现在我们已经看到&#xff0c;区块链领域中许多“玩赚”游戏的失败之处&#xff0c;就是他们试图创造一种…

Hue编辑器命令执行

每一代人都有自己的命中注定的遗憾。遗憾&#xff0c;深深的遗憾。 唯一能自慰的是&#xff0c;我们曾真诚而充满激情地在这个世界上生活过&#xff0c;竭尽全力地劳动过&#xff0c; 并不计代价地将自己的血汗献给了不死的人类之树。 漏洞描述 Hue编辑器存在命令执行漏洞&am…

NFT创作者需要的9个基本工具

NFT创作者需要的9个基本工具 从CRM系统到电子商务平台和移动应用程序&#xff0c;各行各业的企业都前所未有地依赖于数字技术。NFT的世界也是如此——为了保持客户的参与度和粘性&#xff0c;我们需要利用大量的数字平台。 现在有一系列工具&#xff0c;使创建和铸造NFT变得轻…