ExecutorService与CompletionService(ExecutorCompletionService)使用与探究

ExecutorService详解:Java 17线程池管理从零到一 本文深度解析Java 17中ExecutorService线程池管理技术,涵盖线程池核心概念、参数配置、拒绝策略、动态调整及企业级实战案例。通过代码示例详解FixedThreadPool、CachedThreadPool等类型选择,结合监控指标与调优策略,帮助开发者构建高性能、可扩展的并发架构,解决资源竞争与系统过载问题。 阅读详情
好文链接
  1. 深度剖析好文:“既生 ExecutorService, 何生 CompletionService?”
  2. ExecutorCompletionService的使用和实现

1.重大差异:

  • ExecutorService submit()的结果是Future, Future get() 方法的致命缺陷:如果 Future 结果没有完成,调用 get() 方法,程序会阻塞在那里,直至获取返回结果。
  • CompletionService 可以做到获取最先执行完的任务结果。

2.使用方式:

  • executorService.submit()后的结果需要保存在Future中,多个提交的结果保存在List<Future>中。
  • executorCompletionService.submit()的结果直接放在executorCompletionService中了,因为executorCompletionService的内部实现中有自己的队列。
使用示例

使用示例:见 “既生 ExecutorService, 何生 CompletionService?”,以下是复制过来的:
假设我们有 4 个任务(A, B, C, D)用来执行复杂的计算,每个任务的执行时间随着输入参数的不同而不同,如果将任务提交到 ExecutorService, 相信你已经可以“信手拈来”:

ExecutorService

ExecutorService executorService = Executors.newFixedThreadPool(4);
List<Future> futures = new ArrayList<Future<Integer>>();
futures.add(executorService.submit(A));
futures.add(executorService.submit(B));
futures.add(executorService.submit(C));
futures.add(executorService.submit(D));

// 遍历 Future list,通过 get() 方法获取每个 future 结果,这里的 get()会阻塞 
for (Future future:futures) {
    Integer result = future.get();
    // 其他业务逻辑
}

ExecutorCompletionService

ExecutorService executorService = Executors.newFixedThreadPool(4);

// ExecutorCompletionService 是 CompletionService 唯一实现类
CompletionService executorCompletionService= new ExecutorCompletionService<>(executorService );

List<Future> futures = new ArrayList<Future<Integer>>();
futures.add(executorCompletionService.submit(A));
futures.add(executorCompletionService.submit(B));
futures.add(executorCompletionService.submit(C));
futures.add(executorCompletionService.submit(D));

// 遍历 Future list,通过 get() 方法获取每个 future 结果,谁先有结果取谁
for (int i=0; i<futures.size(); i++) {
    Integer result = executorCompletionService.take().get();
    // 其他业务逻辑
}

那么,在executorCompletionService中,使用的List<Future>看起来并不需要,因为直接可以从 executorCompletionService.take().get();中获得结果。我们通过例子进一步验证:
关于这个例子的来源:ExecutorCompletionService的使用和实现

package threads.completeService;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

public class CallableTask implements Callable<Integer> {
  /**
   * 休眠时间
   */
  private int sleepSeconds;
  /**
   * 返回的值
   */
  private int returnValue;

  public CallableTask(int sleepSeconds, int returnValue) {
    this.sleepSeconds = sleepSeconds;
    this.returnValue = returnValue;
  }

  @Override
  public Integer call() throws Exception {
    System.out.println("begin to execute.");

    TimeUnit.SECONDS.sleep(sleepSeconds);

    System.out.println("end to execute.");

    return returnValue;
  }
  
}

public class Main {

  public static void main(String[] args) {
    int taskSize = 5;

    ExecutorService executor = Executors.newFixedThreadPool(taskSize);

    // 构建完成服务
    CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(executor);
    int sleep = 5; // 睡眠时间,单位是秒,不是毫秒
    for (int i = 1; i <= taskSize; i++) {
      int value = i; // 返回结果
      // 向线程池提交任务
      completionService.submit(new CallableTask(sleep, value));//返回结果类型FutureTask
    }

    // 按照完成顺序,打印结果
    for (int i = 0; i < taskSize; i++) {
      try {
        System.out.println(completionService.take().get());// 阻塞,知道有任务完成可以获取结果
        // System.out.println(completionService.poll());//poll直接返回,不阻塞。但是没有完成的任务则返回null
        // System.out.println(completionService.poll(5, TimeUnit.SECONDS));//阻塞等待指定时间,如果有完成结果返回,没有的直接返回null																					// completionService.submit(new RunnableTask(),2);//completionService提交Runnable任务是无法获取结果的

      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (ExecutionException e) {
        e.printStackTrace();
      }
    }

    // 所有任务已经完成,关闭线程池
    System.out.println("执行完毕....");
    executor.shutdown();
  }
}

打印的结果是:

end to execute.
end to execute.
end to execute.
end to execute.
end to execute.
4
5
2
3
1

由于每个线程都sleep5s,谁先执行完具有随机性。我们将结果放在List<Future<Integer>>中,也是可以获取的:

  @Test
  public void test2() throws Exception{
    int taskSize = 5;

    ExecutorService executor = Executors.newFixedThreadPool(taskSize);

    // 构建完成服务
    CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(executor);
    List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
    int sleep = 5; // 睡眠时间,单位是秒,不是毫秒
    for (int i = 1; i <= taskSize; i++) {
      int value = i; // 返回结果
      // 向线程池提交任务
      futures.add(completionService.submit(new CallableTask(sleep, value)));//返回结果类型FutureTask
    }

    // 按照完成顺序,打印结果
    for (int i = 0; i < taskSize; i++) {
      try {
        System.out.println(completionService.take().get());// 阻塞,知道有任务完成可以获取结果
        // System.out.println(completionService.poll());//poll直接返回,不阻塞。但是没有完成的任务则返回null
        // System.out.println(completionService.poll(5, TimeUnit.SECONDS));//阻塞等待指定时间,如果有完成结果返回,没有的直接返回null																					// completionService.submit(new RunnableTask(),2);//completionService提交Runnable任务是无法获取结果的

      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (ExecutionException e) {
        e.printStackTrace();
      }
    }

    for (Future future:futures) {
      System.out.println("futures中取:"+future.get());
    }
    
    // 所有任务已经完成,关闭线程池
    System.out.println("执行完毕....");
    executor.shutdown();
  }

结果如下,从队列中取是按序的:

begin to execute.
begin to execute.
begin to execute.
begin to execute.
begin to execute.
end to execute.
end to execute.
end to execute.
end to execute.
3
4
2
1
end to execute.
5
futures中取:1
futures中取:2
futures中取:3
futures中取:4
futures中取:5
执行完毕....

示例结果表明:ExecutorCompletionService的结果可以直接从ExecutorCompletionService中取出,也可以放到List<Future>中,放到list中可以按序取出。

【第十四篇】CompletionService类源码解析与应用详解【重点】_completionservice的应用 当我们使用ExecutorService启动多个Callable时,每个Callable返回一个Future,而当我们执行Future的get方法获取结果时,可能拿到的Future并不是第一个执行完成的Callable的Future,就会进行阻塞,从而不能获取到第一个完成的Callable结果,那么这样就造成了很严重的性能损耗问题。f1.get();f2.get();f1.get()在获取成功之前会被阻塞,会阻塞c2的执行,严重降低了效率。 阅读详情

相关推荐

Java中ExecutorService线程池的使用(Runnable和Callable多线程实现)

线程的创建和释放,需要占用不小的内存和资源。如果每次需要使用线程时,都new 一个Thread的话,难免会造成资源的浪费,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。不利于扩展,比如如定时执行、定期执行、线程中断,所以很有必要了解下ExecutorService的使用。ExecutorService是Java提供的线程池,也就是说,每次我们需要使用线程的时候,可以通过ExecutorService获得线程。...

BADAO_LIUMANG_QIZHI的博客 8210

java 调用其他线程_java 后台接口另起一个线程执行其他业务

直接post代码,然后在详细介绍为什么:packagecom.xxx.testset.service.impl;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**** @function xxx接口实现类*@authorLiangjw* @date 2019-9-18 下午02:...

weixin_39986060的博客 1217

ExecutorService与CompletionService对比详解.docx

如果 Future 结果没有完成,调用 get() 方法,程序会 阻塞 在那里,直至获取返回结果 先来看第一种实现方式,假设任务 A 由于参数原因,执行时间相对任务 B,C,D 都要长很多,但是按照程序的执行顺序,程序在 get() 任务 A 的执行结果会阻塞在那里,导致任务 B,C,D 的后续任务没办法执行。又因为每个任务执行时间是不固定的, 所以无论怎样调整将任务放到 List 的顺序,都不合适,这就是致命弊端

Java多线程之ExecutorCompletionService

当我们向Executor提交一组任务,并且希望任务在完成后获得结果,此时可以考虑使用。实现了接口。将Executor和功能融合在一起,使用它可以提交我们的Callable任务。这个任务委托给Executor执行,可以使用对象的take和poll方法获取结果。的设计目的在于提供一个可获取线程池执行结果的功能,这个类采用了装饰器模式,需要用户提供一个自定义的线程池,在内部持有该线程池进行线程执行,在原有的线程池功能基础上装饰额外的功能。相比之前Future。

上善若泪 2308

树莓派与无人机协同实战:基于OpenCV的地标识别优化策略

本文深入探讨了基于树莓派与无人机的协同系统,重点分享了利用OpenCV优化地标识别以实现精准降落的实战策略。内容涵盖从应对复杂光照的图像预处理、鲁棒的轮廓几何过滤,到通过ROS进行稳定通信,以及实现分层控制与状态机设计,旨在提升系统在真实环境中的可靠性与性能。

y2z3a4b5c的博客 1085

ADSP-21565的SigmaStudio图形化编程实战:从FW工程改造到音频通道打通

本文详细介绍了如何将ADSP-21569的SigmaStudio图形化编程固件工程改造,以适配ADSP-21565的纯片内SRAM内存架构。通过修改内存映射和链接文件,打通了音频输出通道,并成功利用SigmaStudio进行图形化编程,实现了从白噪声生成到音频输出的完整验证流程。

weixin_29169505的博客 380

java中CompletionService的使用

java中CompletionService的使用 之前的文章中我们讲到了ExecutorService,通过ExecutorService我们可以提交一个个的task,并且返回Future,然后通过调用Future.get方法来返回任务的执行结果。 这种方式虽然有效,但是需要保存每个返回的Future值,还是比较麻烦的,幸好ExecutorService提供了一个invokeAll的方法,来保存...

程序那些事 1万+

C#粘包和分包问题及解决方法

一:通过图解法来描述一下分包和粘包,这样客户更清晰直观的了解:  下面对上面的图进行解释:  1.正常情况:如果Socket Client 发送的数据包,在Socket Server端也是一个一个完整接收的,那个就不会出现粘包和分包情况,数据正常读取。  2.粘包情况:Socket Client发送的数据包,在客户端发送和服务器接收的情况下都有可能发送,因为客户端发送的数据都是发送的一个缓冲...

weixin_42033401的博客 7767

“既生 ExecutorService, 何生 CompletionService?”

| 好看请赞,养成习惯你有一个思想,我有一个思想,我们交换后,一个人就有两个思想If you can NOT explain it simply, you do NOT understa...

码农小胖哥 857

基于Codex Skill的抖音爆款分析与带货视频自动化生成实战

这次我们来看一个基于 Codex 的自动化内容创作项目。核心是利用 Codex 平台的能力,通过自定义的 Skill(技能)来拆解抖音爆款博主的视频模式,并自动生成自己的带货视频。对于内容创作者、电商运营或对短视频自动化感兴趣的技术开发者来说,这是一个将大语言模型(LLM)能力与具体业务场景深度结合的实战案例。 项目的核心价值在于流程自动化。它试图解决一个常见痛点:分析爆款视频的脚本结构、话术、节奏需要大量人工,而模仿创作又耗时费力。通过 Codex 的 Skill 机制,可以将“分析”和“生成”这两个环节

weixin_30420305的博客 382

超分算法 SwinIR: Image Restoration Using Swin Transformer

这篇文章结构比较简单,如果看过Swin-Transformer的话就没什么难点了。作者引入Swin-T结构应用于低级视觉任务,包括图像超分辨率重建、图像去噪、图像压缩伪影去除。网络由一个浅层特征提取模块、深层特征提取模块、重建模块构成。重建模块对不同的任务使用不同的结构。浅层特征提取就是一个3×3的卷积层。深层特征提取是k个RSTB块和一个卷积层构成。RSTB(Res- SwinIR: Image Restoration Using Swin Transformer[ICCV 2021]Abstract1.

qq_45122568的博客 1万+

ExecutorService 和 ExecutorCompletionService 使用区别及ExecutorCompletionService的应用场景

假设我们有这样一个需求,现在有A系统,部署了三个节点。我们需要获取A系统的一个接口数据,需要最快返回返回结果,而不是至少单纯调用某个节点,在某个节点调用不通再去掉用另外一个节点。这种需求如何实现呢?这就是类似Dubbo 中的 Forking Cluster。 其实实现起来也比较简单,我们只需要使用一个线程池同时去调用三个节点,哪个节点获取到了任务就直接返回,并停止其他任务即可。而CompletionService 就是可以这样处理,下面我们对CompletionService 作一个简单的了解吧 Compl

念念不忘,必有回响 993

AutosarMCAL开发——基于EB Wdg驱动

Autosar标准文件中提及的API共有5个,接口名传入参数说明返回参数函数功能ConfigPtr:Wdg配置指针,参数来自于EB生成代码voidWdg初始化ConfigPtr:Wdg配置指针Wdg初始化检查Wdg切换模式,需开启对应配置timeout:设置定时触发器计数(单位ms)void喂狗并重新设定计数值Wdg版本信息本文为博主个人学习总结记录,如有不正,欢迎指正。

qq_45583706的博客 2425

CompletionService的使用场景以及示例

CompletionService用来异步获取ExecutorService的执行结果,因为用了阻塞队列,所以先出的结果先获取。目前只有一个实现类ExecutorCompletionService。 下面是示例Demo:场景是,三个耗时操作分别进行,最后将处理结果给主线程的另一个子线程保存结果。 结构为 CompletionServiceDemo.java package com.example.demo.concurrent.completionservice; import lomb.

MieMieFly的专栏 672

【滚雪球学数学建模】第1节·建模入门+三步法+案例

🎓 本文收录于 《滚雪球学数学建模》专栏,本专栏专注于从零基础出发,带你循序渐进掌握数学建模的核心方法与思维路径。通过“滚雪球式”学习法,从最简单的生活化案例到经典建模工具,再到省赛、国赛真题实战演练,逐步积累知识与技能,帮助你搭建完整的建模体系。无论你是刚接触建模的新生,还是希望提升科研与竞赛能力的学者与工程师,本专栏都将为你提供一条清晰、高效、可实操的建模成长路线,助力你快速进阶,突破难点,迈向数学建模竞赛与实际应用的更高峰 🚀!

**My Coding Family** 6409

铁路场景雷达点云目标识别与追踪系统

本文介绍了一种基于毫米波雷达的铁路货运车站安全监控系统。该系统采用分布式架构,通过多个毫米波雷达节点采集点云数据,经过坐标转换、多雷达融合等处理后,利用机器学习算法实现列车、行人等目标的实时识别与追踪。系统包含数据采集层、处理层、目标识别层、追踪层、预警决策层和可视化层,能够克服传统视频监控受环境影响大的缺点,实现全天候可靠监测。文中详细展示了雷达数据解析和点云预处理的代码实现,包括坐标转换、数据格式解析和体素网格滤波等关键技术。该系统可有效预警铁路场景下的碰撞风险,提升货运车站的安全管理水平。

huanghm88的专栏 125

JUC : ExecutorService → CompletionService → CompletableFuture 进化史

ExecutorService→ CompletionService → CompletableFuture

weixin_55941334的博客 1088

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

多线程CompletionService接口之实现类ExecutorCompletionService

原有Future 对象获取任务的执行状态: package com.thread; /** * @author liuchj * @version 1.0 * @className MyThreadTest * @description //TODO * @date 2019/5/29 **/ import java.util.ArrayList; import java....

javaboy 385

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

CompletionService详解

CompletionService详解

weixin_45428910的博客 1379

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

CompletionService的基本使用以及原理

CompletionService是Java并发编程中的一个工具类,它实现了一个任务完成的队列,并且可以按照任务完成的顺序来获取任务的结果。CompletionService的主要作用是提供一种方式来处理一批并发执行的任务,并且在它们完成后按照完成的顺序获取结果。它通常与ExecutorService一起使用。使用CompletionService可以将一组任务提交给ExecutorService去执行,并且通过调用CompletionService的take()方法来获取已经完成的任务的结果。

qq_39939541的博客 2468

异步编程-ExecutorService、CompletionService、CompletableFuture

1. ExecutorService中submit()和execute()的区别 execute只能提交Runnable类型的任务,无返回值。submit既可以提交Runnable类型的任务,也可以提交Callable类型的任务,会有一个类型为Future的返回值,但当任务类型为Runnable时,返回值为null。 submit()可以进行Exception处理:execute在执行任务时,如果遇到异常会直接抛出,而submit不会直接抛出,而是把异常保存在成员变量中,在FutureTask.get阻塞

Tong_zhi的博客 1421

ExecutorService VS CompletionService

ExecutorService VS CompletionService 1.应用场景:当提交多个任务后,无需保证任务结果的有序性,而且不被时间较长的任务所阻塞,优先处理时间较短的任务时 ExecutorService:多个任务提交之后,获取结果时,如果当前任务未完成,那就阻塞,等到完成才能返回 CompletionService:多个任务提交之后,获取结果时,调用take(),优先获取到已经任务结束的直接返回 2.应用: ExecutorService executorService = Ex

qq_37036963的博客 286

Java中ExecutorService和CompletionService区别

我们现在在Java中使用多线程通常不会直接用Thread对象了,而是会用到java.util.concurrent包下的ExecutorService类来初始化一个线程池供我们使用。 之前我一直习惯自己维护一个list保存submit的callable task所返回的Future对象。 在主线程中遍历这个list并调用Future的get()方法取到Task的返回值。 1 ...

zhangwenlei1404的博客 231

java中executorservice_Java中ExecutorService和CompletionService区别

我们现在在Java中使用多线程通常不会直接用Thread对象了,而是会用到java.util.concurrent包下的ExecutorService类来初始化一个线程池供我们使用。之前我一直习惯自己维护一个list保存submit的callable task所返回的Future对象。在主线程中遍历这个list并调用Future的get()方法取到Task的返回值。public class Com...

weixin_34901508的博客 234

Java并发编程系列之二十八:CompletionService

CompletionService简介CompletionService与ExecutorService类似都可以用来执行线程池的任务,ExecutorService继承了Executor接口,而CompletionService则是一个接口,那么为什么CompletionService不直接继承Executor接口呢?主要是Executor的特性决定的,Executor框架不能完全保证任务执行的异

rhwayfun专栏 1万+
上一篇: 一文总结线程池ThreadPoolExecutor
下一篇: HDFS中的优秀的多线程设计
王小禾
博客等级 码龄11年 80粉丝 291原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值