高并发-ExecutorCompletionService

news2024/12/31 6:02:10

目录

1 为什么要引入高并发

2 ExecutorCompletionService分析

2.1 原理

2.2 api调用分析

3 实操


1 为什么要引入高并发

        众所周知,程序中的代码是从下往下顺序执行的,当我们需要在一个方法中同时执行多个耗时的任务时所消耗时间就会大于等于这些任务消耗的累加时间。那么有没有一种办法可以让这些耗时的任务同时执行呢?这时候就需要并发编程,让这些任务在不同的线程上分别执行,达到理论上的同步执行效果。

2 ExecutorCompletionService分析

2.1 原理

        ExecutorCompletionService实现了CompletionService接口。ExecutorCompletionService将Executor和BlockingQueue功能融合在一起,使用它可以提交我们的Callable任务。这个任务委托给Executor执行,可以使用ExecutorCompletionService对象的take和poll方法获取结果。

        ExecutorCompletionService的设计目的在于提供一个可获取线程池执行结果的功能,这个类采用了装饰器模式,需要用户提供一个自定义的线程池,在ExecutorCompletionService内部持有该线程池进行线程执行,在原有的线程池功能基础上装饰额外的功能。

下面是ExecutorCompletionService的原理图:

        在使用ExecutorCompletionService时需要提供一个自定义的线程池Executor,构造ExecutorCompletionService。同时,也可以指定一个自定义的队列作为线程执行结果的容器,当线程执行完成时,通过重写FutureTask#done()将结果压入队列中。

        当用户把所有的任务都提交了以后,可通过ExecutorCompletionService#poll方法来弹出已完成的结果,这样做的好处是可以节省获取完成结果的时间。

        下面是使用队列和不使用队列的流程对比,从图中我们可以看出,在使用队列的场景下,我们可以优先获取到完成的线程,当我们要汇总所有的执行结果时,这无疑会缩减我们的汇总时间。

        而不使用队列时,我们需要对FutureTask进行遍历,因为我们不知道哪个线程先执行完了,只能挨个去获取结果,这样已经完成的线程会因为前面未完成的线程的耗时而无法提前进行汇总。

汇总结果的耗时时间 :

在使用队列的场景下,我们可以在其他任务线程执行的过程中汇总已完成的结果,节省汇总时间。不使用队列的场景下,只用等到当前的线程执行完成才能汇总。 

2.2 api调用分析

ExecutorCompletionService实现了CompletionService接口,CompletionService的方法有以下:

  • Future submit(Callable task):提交一个Callable类型任务,并返回该任务执行结果关联的Future;
  • Future submit(Runnable task,V result):提交一个Runnable类型任务,并返回该任务执行结果关联的Future;
  • Future take():从内部阻塞队列中获取并移除第一个执行完成的任务,阻塞,直到有任务完成;
  • Future poll():从内部阻塞队列中获取并移除第一个执行完成的任务,获取不到则返回null,不阻塞;
  • Future poll(long timeout, TimeUnit unit):从内部阻塞队列中获取并移除第一个执行完成的任务,阻塞时间为timeout,获取不到则返回null;

ExecutorCompletionService结构源码如下所示: 

 ExecutorCompletionService这两个构造方法,源码如下:

public ExecutorCompletionService(Executor executor) {
    if (executor == null)
        throw new NullPointerException();
    this.executor = executor;
    this.aes = (executor instanceof AbstractExecutorService) ?
        (AbstractExecutorService) executor : null;
    this.completionQueue = new LinkedBlockingQueue<Future<V>>();
}

public ExecutorCompletionService(Executor executor,
                                 BlockingQueue<Future<V>> completionQueue) {
    if (executor == null || completionQueue == null)
        throw new NullPointerException();
    this.executor = executor;
    this.aes = (executor instanceof AbstractExecutorService) ?
        (AbstractExecutorService) executor : null;
    this.completionQueue = completionQueue;
}

也就是说新建ExecutorCompletionService实例对象的时候,可以自行指定阻塞队列的类型。

阻塞队列:在Java多线程编程中,阻塞队列是一种特殊的队列,它可以在队列为空时阻塞获取元素的线程,也可以在队列已满时阻塞插入元素的线程。这种队列通常用于实现生产者-消费者模式,其中生产者线程向队列中插入任务,消费者线程从队列中取出任务并执行。Java中提供了多种类型的阻塞队列,包括:

  • ArrayBlockingQueue:基于数组实现的有界阻塞队列,按照先进先出的原则进行元素插入和移除。
  • LinkedBlockingQueue:基于链表实现的可选有界阻塞队列,按照先进先出的原则进行元素插入和移除。
  • PriorityBlockingQueue:基于优先级堆实现的无界阻塞队列,元素按照优先级顺序进行插入和移除。
  • SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等待一个相应的删除操作,反之亦然。
  • DelayQueue:一个基于优先级堆实现的延迟阻塞队列,其中的元素只有在其指定的延迟时间到达后才能被取出。

这些阻塞队列都是线程安全的,可以在多线程环境下使用。不同的阻塞队列适用于不同的场景,可以根据自己的需求选择合适的队列。如果新建实例对象时不指定阻塞队列类型,默认使用的是LinkedBlockingQueue。

3 实操

public class TestMain1 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        ExecutorCompletionService<Long> objectExecutorCompletionService = new ExecutorCompletionService<>(executor);
        for (int i = 0; i < 5; i++) {
            MyTask myTask = new MyTask();
            objectExecutorCompletionService.submit(myTask);
        }
        for (int i = 0; i < 5; i++) {
            Future<Long> future = objectExecutorCompletionService.poll(3,TimeUnit.MILLISECONDS);
            Long result = future.get();
            System.out.println("Result from Thread " + (i + 1) + ": " + result);
        }
        executor.shutdown();
    }
}

public class MyTask implements Callable<Long> {

    @Override
    public Long call() throws Exception {
        return Thread.currentThread().getId();
    }
}

需要注意的问题
1、调用poll方法产生的空指针
调用限制时长的poll()方法时,需要合理的设定时间,否则会返回null,容易引发空指针问题

2、需要注意OOM
调用ExecutorCompletionService实例对象后,需要及时的进行take()或者poll()操作,否则执行的结果会不停的堆积在队列中,占用堆内存,最终导致oom
 

文章参考:初探高并发—ExecutorCompletionService_一条有梦想的咸鱼-的博客-CSDN博客

 

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

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

相关文章

港陆证券:五日线破位怎么看?

在股票交易中&#xff0c;五日线是个重要的技术指标之一&#xff0c;它能够反映出最近的商场趋势。假如五日线破位&#xff0c;这意味着商场呈现了趋势反转&#xff0c;出资者需求注重趋势改动&#xff0c;并采取相应的出资战略。 首先&#xff0c;咱们来看看五日线破位的原因…

修改PX4飞控的imu频率

QGroundControl 连接上飞控后&#xff0c;打开 Analyze Tools 下的 MAVLink Inspector 界面 可以看到当前的 IMU 频率为50 HZ&#xff0c;或者在终端启动 mavros&#xff0c;终端输入 sudo chmod 777 /dev/ttyACM0 roslaunch mavros px4.launch 然后查看频率 rostopic hz /m…

备份StarRocks数据到对象存储minio中/外表查minio中的数据

1.部署minio环境 docker pull minio/minio宿主机与容器挂在映射 宿主机位置容器位置/data/minio/config/data/data/minio/data/root/.minio 拉起环境&#xff1a; docker run -p 9000:9000 -p 9090:9090 --name minio \ -d --restartalways \ -e "MINIO_ACCESS_KEYadm…

uniapp的小程序中使用web-view进行相互传参,并监听web-view的返回键

uniapp的小程序中使用web-view进行相互传参&#xff0c;并监听web-view的返回键 一、unaipp给webview传参 //uniapp页面中 <web-view :src"src" message"getMessage" onPostMessage"getPostMessage"></web-view>data() {return …

Mybatis学习|Mybatis缓存:一级缓存、二级缓存

Mybatis缓存 MyBatis包含一个非常强大的查询缓存特性&#xff0c;它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。 MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存 默认情况下&#xff0c;只有一级缓存开启。(SqlSession级别的缓存&#xff0c;也称为本地…

github无法访问

1.查看ip ipaddress.com 2.地址如下&#xff1a; 3.修改本地host文件 &#xff08;1&#xff09;打开访达后&#xff0c;在键盘上按ShiftCommandG组合键&#xff0c;进入&#xff0c;在etc找到host文件&#xff0c;修改 &#xff08;2&#xff09;如果修改不成功&#xff0…

LeetCode 47题:全排列2

题目 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[…

【C++】C++11新特性 可变参数模板

可变参数模板 可变参数模板1、基本介绍2、递归函数方式展开参数包3、逗号表达式展开参数包 可变参数模板 1、基本介绍 C11的新特性可变参数模板能够让你创建可以接受可变参数的函数模板和类模板&#xff0c;相比C98/03&#xff0c;类模版和函数模版中只能含固定数量的模版参数…

将 ChatGPT 用于数据科学项目的指南

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 我们都知道 ChatGPT 的受欢迎程度以及人们如何使用它来提高生产力。但是&#xff0c;如果您是新手&#xff0c;则值得注册ChatGPT免费演示并尝试它所能做的一切。您还应该参加我们的 ChatGPT 简介课程&#xff0c;学习…

文旅品牌为何青睐于3D虚拟数字人定制?

随着web3.0技术的到来&#xff0c;数字人技术快速发展&#xff0c;推动着文旅通过3D虚拟数字人定制&#xff0c;探索数字化营销。数字人结合动捕设备&#xff0c;可以颠覆传统玩法&#xff0c;以数字人内容赋能传统宣传手段&#xff0c;通过动捕设备让数字人与用户交流互动&…

U盾难管理?用U盾专用USB集线器

公司有一堆U盾要插着用&#xff0c;但是一台电脑也才两三个接口&#xff0c;怎么办&#xff1f; 三个字&#xff0c;很简单&#xff0c; 一台U盾专用的USB集线器就能解决。 U盾专用集线器为解决网银U盾连接问题而生。 它有四大好处&#xff01; 集中管理 把所有U盾集中到一…

Java泛型(待补充)

泛型是一种“代码模板”&#xff0c;可以用一套代码套用各种类型。 一、什么是泛型&#xff1f; 泛型就是编写模板代码来适应任意类型&#xff1b;泛型的好处是使用时不必对类型进行强制转换&#xff0c;它通过编译器对类型进行检查&#xff1b;注意泛型的继承关系&#xff1a…

RHCE——十七、文本搜索工具-grep、正则表达式

RHCE 一、文本搜索工具--grep1、作用2、格式3、参数4、注意5、示例5.1 操作对象文件&#xff1a;/etc/passwd5.2 grep过滤命令示例 二、正则表达式1、概念2、基本正则表达式2.1 常见元字符2.2 POSIX字符类2.3 示例 3、扩展正则表达式3.1 概念3.2 示例 三、作业1、作业一2、作业…

【Apollo】开启Apollo之旅:让自动驾驶如此简单

前言 Apollo 是百度公司推出的自动驾驶平台。它是一个综合性的自动驾驶解决方案&#xff0c;提供了包括感知、决策、规划和控制等核心功能&#xff0c;以及地图、定位、仿真、数据管理等配套工具。 文章目录 前言Apollo 的发展历程Apollo 8.0新特性软件包管理感知框架工具链小…

软件确认测试的七大准则

确认测试 1. 确认软件设计是否依从于软件需求&#xff0c;且软件的每一项需求是否能跟踪到软件设计。 2. 确认状态顺序和状态变化( 功能模块图) 。 3. 确认数据和控制流满足安全性、功能性和性能需求。 4. 确认软件的功能性&#xff0c;硬件、软件和用户接口的一致性&#…

上海亚商投顾:沪指放量大涨超1% 北向资金净买入近70亿元

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日集体反弹&#xff0c;沪指高开高走涨超1%&#xff0c;上证50盘中涨超2%&#xff0c;北证50指数涨…

涉案财物管理系统DW-S405|实现涉案财物智能化管理

涉案财物管理系统&#xff08;智财物DW-S405&#xff09;是依托互3D技术、云计算、大数据、RFID技术、数据库技术、AI、视频分析技术对RFID智能仓库进行统一管理、分析的信息化、智能化、规范化的系统。 东识涉案财物管理系统是一套基于物联网技术的管理方案&#xff0c;旨在规…

孙哥Spring源码第17集

第17集 refresh()-invokeBeanFactoryPostProcessor -一-invokeBeanFactoryPostProcessor的分析过程 【视频来源于&#xff1a;B站up主孙帅suns Spring源码视频】 1、什么是解析顶级注解&#xff1f; PropertySource CompeontScan Configuration Component ImportResour…

第14章 热门数据实时收集

mini商城第14章 热门数据实时收集 一、课题 商品秒杀-热门数据实时收集 二、回顾 1、秒杀设计 2、活动管理 3、搜索管理 4、商品详情处理 5、 数据同步 三、目标 1、掌握热门分析收集方案 2、Lua高级语法 掌握Lua高级语法指令执行顺序 掌握Lua高级语法指令编写位置 …

FPGA GTH 全网最细讲解,aurora 8b/10b编解码,HDMI视频传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、GTH 全网最细解读GTH 基本结构GTH 发送和接收处理流程GTH 的参考时钟GTH 发送接口GTH 接收接口GTH IP核调用和使用 4、设计思路框架视频源选择silicon9011解码芯片配置及采集动态彩条视频数据组包GTH aurora 8b/10…