Java并发基础:CompletionService全面解析!

news2024/11/15 11:11:02

Java并发基础:CompletionService全面解析! - 程序员古德

内容概要

CompletionService的优点在于能够解耦任务提交与结果获取,有效的整合线程池与阻塞队列,实现任务完成顺序的处理,提升系统吞吐量,它简化了多线程编程的复杂性,使开发者能够更专注于业务逻辑,而不必过多关注线程管理细节。

核心概念

CompletionService是一个结合了ExecutorBlockingQueue功能的服务,它主要用于解决异步任务执行中的两个问题:

  1. 任务管理和结果收集:当有一组并行或异步执行的任务,并且想要以它们完成的顺序(而不是启动的顺序)收集结果时,CompletionService就非常适合,它提交任务给Executor去执行,并在任务完成时,将结果放入一个阻塞队列中,这样可以从队列中取出已完成的任务结果,而不需要知道具体是哪个任务先完成。
  2. 提高资源利用率:在传统的多线程任务执行中,如果某些任务执行得比其他任务快得多,那么等待所有任务完成可能会浪费资源(如CPU的时间),使用CompletionService,可以立即处理已完成的任务,而不必等待其他较慢的任务,这种即时的任务处理方式可以减少资源空闲时间,提高整体系统的吞吐量和响应速度。

CompletionService主要用来解决异步任务执行中的任务管理和结果收集问题,以及通过优化任务处理顺序来提高资源利用率,这使得它非常适合于处理大量并行任务,并且需要按照完成顺序处理结果的场景。

官方文档:https://docx.iamqiang.com/jdk11/api/java.base/java/util/concurrent/CompletionService.html

代码案例

import java.util.concurrent.*;  
  
// 任务类,实现了Callable接口,用于异步计算  
class ComputationTask implements Callable<Integer> {  
    private final int number;  
  
    public ComputationTask(int number) {  
        this.number = number;  
    }  
  
    @Override  
    public Integer call() throws Exception {  
        // 模拟耗时计算,比如计算一个数的平方  
        int result = number * number;  
        // 让线程睡眠一段时间来模拟不同的任务执行时间  
        Thread.sleep(number * 100);  
        return result;  
    }  
}  
  
public class CompletionServiceDemo {  
  
    public static void main(String[] args) throws InterruptedException, ExecutionException {  
        // 创建一个固定大小的线程池  
        ExecutorService executor = Executors.newFixedThreadPool(4);  
          
        // 创建一个CompletionService,用于管理异步任务的完成  
        CompletionService<Integer> completionService = new ExecutorCompletionService<>(executor);  
          
        // 提交一些异步任务到CompletionService  
        for (int i = 1; i <= 5; i++) {  
            completionService.submit(new ComputationTask(i));  
        }  
          
        // 从CompletionService中获取并处理已完成的任务结果  
        for (int i = 0; i < 5; i++) {  
            // take() 方法会阻塞,直到有任务完成  
            Future<Integer> future = completionService.take();  
            // 获取任务的结果  
            Integer result = future.get();  
            // 输出结果  
            System.out.println("Result: " + result);  
        }  
          
        // 关闭线程池  
        executor.shutdown();  
        // 等待所有任务完成  
        executor.awaitTermination(1, TimeUnit.MINUTES);  
    }  
}

在上面代码中,ComputationTask是一个简单的任务类,它实现Callable接口来计算一个数的平方,并通过Thread.sleep模拟了不同的任务执行时间。

main方法中,创建了一个固定大小的线程池和一个CompletionService,然后,我们提交了5个ComputationTaskCompletionService,接着,使用一个循环来从CompletionService中获取已完成的任务,并输出它们的结果,注意,completionService.take()会阻塞直到有一个任务完成。

运行代码会输出如下内容:

Result: 1  
Result: 4  
Result: 9  
Result: 16  
Result: 25

注意:CompletionService确保了可以按照任务完成的顺序来处理结果,而不是按照任务提交的顺序。

核心API

CompletionService结合了ExecutorBlockingQueue的功能,用于处理异步任务的执行和结果的收集,CompletionService将生产新异步任务和消费已完成任务的结果分离开来,使得可以以任务完成的顺序而不是提交的顺序来获取结果,下面是CompletionService中主要方法的含义:

1、Future<V> take() throws InterruptedException:这个方法从完成队列中移除并返回已完成的Future,如果当前没有已完成的Future,则此方法会阻塞直到有结果可用。

2、Future<V> poll():这个方法尝试从完成队列中获取并移除一个已完成的Future,如果当前没有已完成的Future,则此方法会立即返回null而不会阻塞。

3、Future<V> poll(long timeout, TimeUnit unit):这个方法尝试在给定的超时时间内从完成队列中获取并移除一个已完成的Future,如果在超时时间内没有可用的结果,则返回null

4、void submit(Callable<T> task):提交一个Callable任务用于执行,并返回一个表示该任务的未决结果的Future,这个任务是由关联的Executor来执行的。

5、Future<Void> submit(Runnable task, V result):提交一个Runnable任务用于执行,并返回一个表示该任务的未决结果的Future,这个方法还允许你为Runnable任务提供一个结果,这个结果将在Future.get()方法被调用时返回,这个任务是由关联的Executor来执行的。

6、Future<Void> submit(Runnable task):提交一个Runnable任务用于执行,并返回一个表示该任务的未决结果的Future,因为这个任务是Runnable,所以Future.get()方法返回null,这个任务是由关联的Executor来执行的。

CompletionService只是一个接口,本身并不直接实现这些方法,而是通过具体的实现类(如ExecutorCompletionService)来提供这些方法的具体实现。ExecutorCompletionServiceExecutorBlockingQueue结合在一起,可以将CallableRunnable任务提交给Executor执行,并通过CompletionService按照它们完成的顺序来检索结果。

核心总结

【揭秘】RecursiveTask全面解析 - 程序员古德

CompletionService结合了Executor和BlockingQueue的功能,可以异步地提交任务并获取它们的结果,它最大的优点就是任务完成顺序与提交顺序无关,先完成的任务可以先获取结果,这大大提高了处理效率。

此外,它还能很好地处理异常,确保我们在获取结果时不会因某个任务的异常而阻塞,但是,它在某些场景下可能略显复杂,例如,业务要求严格按照任务提交的顺序来获取结果,CompletionService就不那么适用了。

此外,它并不能直接取消已经提交但尚未开始执行的任务,这在某些需要灵活控制任务执行的场景中可能会带来不便。

关注我,每天学习互联网编程技术 - 程序员古德

END!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1423008.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【昕宝爸爸小模块】深入浅出详解之常见的语法糖

深入浅出详解之常见的语法糖 一、&#x1f7e2;关于语法糖的典型解析二、&#x1f7e2;如何解语法糖&#xff1f;2.1&#x1f7e2;糖块一、switch 支持 String 与枚举2.2&#x1f4d9;糖块二、泛型2.3&#x1f4dd;糖块三、自动装箱与拆箱2.4&#x1f341;糖块四、方法变长参数…

TOP100 矩阵

1.73. 矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 提示&#xff1a; m matrix.lengthn matrix[0].length1 < m, n < 200-2^31 < matrix[i][j] < 2^31 - 1 思路&#xf…

宏景eHR FrCodeAddTreeServlet SQL注入漏洞复现

前言 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 一、产…

【排序算法】C语言实现随机快排,巨详细讲解

文章目录 &#x1f680;前言&#x1f680;快排的核心过程partition&#xff08;划分过程&#xff09;&#x1f680;快排1.0&#x1f680;随机快速排序&#x1f680;稳定性 &#x1f680;前言 铁子们好啊&#xff01;继续我们排序算法今天要讲的是快排&#xff0c;通常大家所说…

❤搭建一个Springboot项目(ltbjava)

❤从0实现一个项目 搭建好我们的java环境和运行的IDEA软件以后&#xff0c;接下来我们就应该实现一个自己的项目了 0 项目描述 基于jdk17 的学习&#xff0c;因为据说最新的spring框架的最低要求是jdk17Maven 3.8.7PS&#xff1a;springboot3.0版本以上必须用jdk171、 项目创…

STM32F407移植OpenHarmony笔记6

继上一篇笔记&#xff0c;编译好STM32的裸机程序&#xff0c;能点亮LED灯了。 下一步就是启动liteos_m内核了。 不过为了更好的调试代码&#xff0c;需要先把printf重定向到串口&#xff0c;基于gcc的printf重定向和Keil不一样。 直接新建printf.c&#xff0c;在里面重写printf…

摄像头监控系统/视频监控云平台EasyCVR接入单兵设备后如何配置移动规矩

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体控可实现视频监控直播、视频轮播、视频录像…

C#学习笔记_类(Class)

类的定义 类的定义是以关键字 class 开始&#xff0c;后跟类的名称。类的主体&#xff0c;包含在一对花括号内。 语法格式如下&#xff1a; 访问标识符 class 类名 {//变量定义访问标识符 数据类型 变量名;访问标识符 数据类型 变量名;访问标识符 数据类型 变量名;......//方…

氢气泄漏检测仪使用方法:守护安全,从细节开始

随着科技的发展&#xff0c;我们的生活和工作环境中充满了各种潜在的危险。其中&#xff0c;氢气作为一种清洁能源&#xff0c;其使用日益广泛&#xff0c;但同时也带来了泄漏的风险。为了确保我们的安全&#xff0c;了解并正确使用氢气泄漏检测仪至关重要。下面将详细介绍氢气…

yum一直出现正在尝试其它镜像... 解决方法

更改yum镜像源地址为阿里云镜像即可 1. 去ail云yum镜像源官网 阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 (aliyun.com) 2. 选择自己对应的操作系统这里以centos7演示&#xff1a; 3. 先备份原yum配置文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Ce…

OC源码 - FailureDetectionPeriodBlockMinutes参数解读

FailureDetectionPeriodBlockMinutes 看看官方文档中对该参数如何描述 orchestrator will detect failures to your topology, always. As a matter of configuration you may set the polling frequency and specific ways for orchestrator to notify you on such detectio…

Selenium处理Alert弹窗

页面弹窗有 3 种类型&#xff1a; alert&#xff08;警告信息&#xff09; confirm&#xff08;确认信息&#xff09; prompt&#xff08;提示输入&#xff09; 对于页面出现的 alert 弹窗&#xff0c;Selenium 提供如下方法&#xff1a; 序号 方法/属性 描述 1 ac…

【Delphi】IDE 工具栏错乱恢复

由于经常会在4K和2K显示器上切换Delphi开发环境(IDE)&#xff0c;导致IDE工具栏错乱&#xff0c;咋样设置都无法恢复&#xff0c;后来看到红鱼儿的博客&#xff0c;说是通过操作注册表的方法&#xff0c;能解决&#xff0c;试了一下&#xff0c;果真好用&#xff0c;非常感谢分…

Linux split命令 切割文件

目录 一. 主要配置项二. 按照行数切割文件三. 按照指定大小切割文件 一. 主要配置项 ⏹将文件按照行数或者大小切割为若干份小文件&#xff0c;主要作用就是用来切割文件 -l&#xff1a;表示将文件按照行分割-d&#xff1a;表示使用数字作为分割后的文件名后缀, 而不是默认的…

java生成dll,并利用c语言使用libcurl调用http接口

本文可能需要使用的环境和工具&#xff1a; c/ c和GCC编译器 (Windows) Cygwin或MinGW 本文运行环境为windows10&#xff0c;使用MinGW-W64-builds-4.2.0 curl-8.5.0 libcurl 可以在官网 http://curl.haxx.se/ 获得。 配置MinGW 将mingw.rar解压到D:&#xff0c;修改系统…

软件压力测试:探究其目的与重要性

随着软件应用在各行各业中的广泛应用&#xff0c;确保软件在高负载和极端条件下的稳定性变得至关重要。软件压力测试是一种验证系统在不同负载条件下的性能和稳定性的方法。本文将介绍软件压力测试的目的以及为什么它对软件开发和部署过程至关重要。 验证系统性能的极限&#x…

C#: 软件任务栏托盘图标添加关闭软件菜单等

说明&#xff1a;在软件在任务栏右下角的系统托盘的图标添加个右键弹出菜单功能&#xff0c;案例实现右键弹窗菜单关闭软件功能。 1.添加系统托盘图标控件 NotifyIcon 2.右键打开控件属性菜单添加鼠标点击事件函数 3.事件函数添加代码 //右键点击任务栏图标弹出关闭菜单 priv…

python爬虫之豆瓣首页图片爬取

网址&#xff1a;https://movie.douban.com/ import requests from lxml import etree import re url https://movie.douban.com headers {User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.289 Safari/5…

【Java-JDK】JDK 的安装与环境变量的配置:Windows Linux

【Java-JDK】JDK的安装与环境变量的配置&#xff1a;Windows & Linux 1&#xff09;Windows安装JDK1.1.下载JDK1.1.安装JDK1.2.JDK环境配置1.3.验证环境变量是否配置成功 2&#xff09;Linux安装JDK2.1.下载JDK2.2.安装JDK2.3.JDK环境配置2.4.验证环境变量配置是否成功 1&a…

OpenFeign认证上下文信息的传递

基本思路 其中网关部分不是本章讨论的范围,网关处理与后续服务的处理类似。 发送处理:将认证信息植入到请求信息中接收处理:从请求头中获取到认证信息,并解析为用户信息,供后续业务使用。有两个思路: 将认证信息放到请求头中,向下传递。这种方式适用于用户认证上下文中信…