Java ~ Executor ~ ExecutorCompletionService【总结】

news2024/12/29 11:14:02

前言


 文章

  • 相关系列:《Java ~ Executor【目录】》(持续更新)
  • 相关系列:《Java ~ Executor ~ ExecutorCompletionService【源码】》(学习过程/多有漏误/仅作参考/不再更新)
  • 相关系列:《Java ~ Executor ~ ExecutorCompletionService【总结】》(学习总结/最新最准/持续更新)
  • 相关系列:《Java ~ Executor ~ ExecutorCompletionService【问题】》(学习解答/持续更新)
  • 涉及内容:《Java ~ Executor【总结】》
  • 涉及内容:《Java ~ Executor ~ AbstractExecutorService【总结】》
  • 涉及内容:《Java ~ Executor ~ CompletionService【总结】》
  • 涉及内容:《Java ~ Executor ~ Future【总结】》
  • 涉及内容:《Java ~ Executor ~ RunnableFuture【总结】》
  • 涉及内容:《Java ~ Executor ~ FutureTask【总结】》
  • 涉及内容:《Java ~ Executor ~ Callable【总结】》
  • 涉及内容:《Java ~ Collection/Executor ~ PriorityBlockingQueue【总结】》
  • 涉及内容:《Java ~ Collection ~ PriorityQueue【总结】》
  • 涉及内容:《Java ~ Thread ~ Runnable【总结】》

一 概述


 简介

    任务的“生产”与“消费”默认是同步的。在正式讲述ExecutorCompletionService(执行器完成服务)类的作用之前我们需要先了解所谓任务的“生产”与“消费”是什么概念。在Executor(执行器)框架中任务的“生产”指任务向执行器递交的行为,而“消费”则指将任务从执行器中移除的行为,即执行器不再持有任务的引用,因此“消费”只能在任务执行结束后(完成/异常/取消)后发生。任务的“生产”与“消费”通常被认为是同步的,这是一个会让初学者非常疑惑的点,因为基于大多数执行器接口实现类都采用异步执行方案的原因,并无法保证递交方法会在任务“消费”后返回,因此同步就显得毫无道理。那为什么还会有同步的说法呢?这是因为递交方法同步返回的Future(未来)拥有追踪任务执行状态的能力。因此即使任务被执行器异步执行,也可在需要时通过调用未来的get()方法达到同步“消费”(并获取执行结果/异常)的目的,其效果与任务在递交时即被同步“消费”是等价的,因此任务的“生产”与“消费”本质是一种间接/变相的同步。

    同步“消费”的前提是确定具体需要被“消费”的任务。想要进行同步“消费”就必须先确定具体需要被“消费”的任务,这其中原因是因为我们需要调用该任务关联未来的get()方法。这并没有想象中简单,因为递交返回的未来未必是我们想要的目标未来,即递交的任务未必是我们想“消费”的任务。典型的例子是:如何获取一组递交任务中最早执行结束(完成/异常/取消)任务的结果呢?事实上开发者应该很清楚该问题在使用同步“消费”的情况下是无法/很难解决的,因为无法得知哪个同步未来的代表任务会最早执行结束(完成/异常/取消)。因此在包含上述举例在内的某些场景中我们也希望“消费”可以是异步的,即不通过调用同步未来get()方法的方式来“消费”任务,以达到对任务“消费”的顺序/时间/条件等多项维度进行自定义的目的。

    CompletionService(完成服务)接口在定义上提供将任务的“生产”与“消费”从概念上分离的能力,而执行器完成服务类实现了这种能力,并支持按结束(完成/异常/取消)顺序对任务进行异步“消费”。完成服务接口在递交方法的基础上额外定义了移除方法对递交至完成服务的任务进行“消费”(并返回相关的未来),使得任务的“生产”与“消费”之间失去了交集而由原本的同步关系转变为了异步关系。因此作为完成服务接口的唯一实现类,执行器完成服务类天然具有分离任务“生产”与“消费”的能力。并且为了实现上述获取一组递交任务中最早执行结束(完成/异常/取消)任务结果的需求,执行器完成服务类会按结束(完成/异常/取消)的顺序对任务进行异步“消费”,即先被异步“消费”的任务一定比后被异步“消费”的任务先执行结束(完成/异常/取消)。该功能是通过代理将结束(完成/异常/取消)的任务依次加入阻塞队列中实现的,该功能会在下文详述。任务被异步“消费”后调用异步未来的get()方法,此时的get()方法已不再具有同步“消费”的意义,只单纯的被用来获取任务的执行结果。

三 创建


  • public ExecutorCompletionService(Executor executor) —— 创建指定执行器,且完成队列默认为链接阻塞队列的执行器完成服务。

  • public ExecutorCompletionService(Executor executor, BlockingQueue<Future> completionQueue) —— 创建指定执行器及完成队列的执行器完成服务。

四 方法


 递交

  • public Future<V> submit(Callable task) —— 递交 —— 向当前执行器完成服务递交指定可回调/任务,并返回可追踪/获取指定可回调/任务执行状态/结果/异常的未来,但不推荐使用该未来等待指定可回调/任务执行结束。

  • public Future<V> submit(Runnable task, V result) —— 递交 —— 向当前执行器完成服务递交指定可运行/任务,并返回可追踪/获取指定可运行/任务执行状态/结果/异常的未来,但不推荐使用该未来等待指定可运行/任务执行结束。方法会同步传入用于承载指定可运行/任务执行结果/异常的变量,承载后指定可运行/任务执行结果/异常即可通过变量直接获取,也会向未来传递,因此该方法返回未来的get()方法可获取指定可运行/任务的执行结果/异常。

 移除

  • public Future<V> poll() —— 轮询 —— 从当前执行器完成服务中移除并获取下个结束(完成/异常/取消)任务。该方法是移除方法“特殊值”形式的实现,当当前执行器完成服务存在结束(完成/异常/取消)任务时移除并返回下个结束(完成/异常/取消)任务;否则返回null。

  • public Future<V> take() throws InterruptedException —— 拿取 —— 从当前执行器完成服务中移除并获取下个结束(完成/异常/取消)任务。该方法是移除方法“阻塞”形式的实现,当当前执行器完成服务存在结束(完成/异常/取消)任务时移除并返回下个结束(完成/异常/取消)任务;否则等待至存在结束(完成/异常/取消)任务为止。

  • public Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException —— 轮询 —— 从当前执行器完成服务中移除并获取下个结束(完成/异常/取消)任务。该方法是移除方法“超时”形式的实现,当当前执行器完成服务存在结束(完成/异常/取消)任务时移除并返回下个结束(完成/异常/取消)任务;否则在指定等待时间内等待至存在结束(完成/异常/取消)任务为止,超出指定等待时间则返回null。

五 实现


在这里插入图片描述

 完成队列

    [completionQueue & 完成队列]是执行器完成服务类用于暂存未来的容器,结束(完成/异常/取消)任务的关联未来会被插入[完成队列]中,等待被移除/异步“消费”。执行器完成服务类设计[完成队列]有两个目的:一是将之作为异步“消费”的统一出口,即执行器完成服务类移除方法的本质其实就是从[完成队列]中移除未来并返回;二是基于队列的结构顺序实现按结束(完成/异常/取消)顺序异步“消费”任务的功能。因为除PriorityQueue(优先级队列)类、PriorityBlockingQueue(优先级阻塞队列)类及少数具备特殊功能的实现外,队列通常呈现FIFO(先入先出)的操作顺序。因此如果能够保证未来以代表任务的结束(完成/异常/取消)顺序插入[完成队列],就能够保证其按同样的顺序从[完成队列]中移除,这就达到了按结束(完成/异常/取消)顺序异步“消费”任务的目的。

 执行/封装/钩子

    注意:以下讲述内容需要对未来相关内容有一定的了解,否则可能难以理解关于封装的部分内容。

    执行器完成服务类通过组合执行器提供对任务的间接执行能力。想要令未来以代表任务的结束(完成/异常/取消)顺序插入[完成队列],首先就需要解决任务的执行问题。执行器完成服务类并不应该具备任务的直接执行能力,即不依赖任何执行器独立执行任务。因为这会导致执行器异步“消费”时任务的执行脱离自身的控制,从而导致各种难以控制的后果发生,例如任务的执行时间错误、执行性能降低及执行结果不正确等。因此基于以上原因,执行器完成服务类选择通过组合[executor & 执行器]的方式提供对任务的间接执行能力。[执行器]会在创建执行器完成服务时具体指定,由此任务的执行还是会由外部调用执行器完成服务的执行器直接负责,这使得执行器完成服务类可与任何执行器配合使用。

    执行器完成服务类通过重写钩子的方式令未来在代表任务结束(完成/异常/取消)时自动插入[完成队列]。所谓的钩子是指FutureTask(未来任务)类定义的done()方法,该方法默认为空实现,并且会在任务结束(完成/异常/取消)时调用,因此执行器完成服务类通过自实现私有内部类QueueingFuture(排队未来)的方式重写了该方法,用于在任务结束(完成/异常/取消)时将其关联未来加入到[完成队列]中。

    执行器完成服务类会将递交的任务二度封装为排队未来。递交至执行器完成服务的任务需要先进行一度封装为未来用于在异步“消费”时返回。关于任务具体会被一度封装哪种未来与执行器完成服务的[执行器]有关,如果[执行器]为AbstractExecutorService(抽象执行器服务)类型,则其还会被转化保存在[aes & 抽象执行器服务]中用于将任务一度封装为[执行器]指定的RunnableFuture(可运行未来)接口实现类类型未来;否则固定将任务一度封装为未来任务。随后完成一度封装获得的未来会被继续二度封装为排队未来,并最终递交至[执行器]执行。排队未来类组合了[task & 任务]持有未来的引用,当任务执行结束(完成/异常/取消)并调用done()方法时,会将[任务]加入到[完成队列]中…相关源码如下:

private final BlockingQueue<Future<V>> completionQueue;

/**
 * FutureTask extension to enqueue upon completion
 * 未来任务衍生在完成后入队
 */
private class QueueingFuture extends FutureTask<Void> {

    QueueingFuture(RunnableFuture<V> task) {
        super(task, null);
        this.task = task;
    }

    @Override
    protected void done() {
        // 将未来加入[完成队列]
        completionQueue.add(task);
    }
    
    // 持有一度封装后未来的引用
    private final Future<V> task;

}

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

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

相关文章

如何做需求分析

目录 核心理念&#xff1a; 主要目的&#xff1a; 具体思路&#xff1a; 注意事项&#xff1a; 核心理念&#xff1a; 首先需要想清楚一个问题&#xff1a;作为一个测试&#xff0c;有没有把需求当作产品中的一个组成部分&#xff0c;然后尽到一个测试的责任与义务&#x…

JavaScript中truthy(真值)或者Falsy(假值)

● 在JavaScript中&#xff0c;有五个值是falsy ○ 0 ○ ’ ’ ○ undefined ○ null ○ NaN 除此之外&#xff0c;任何不是空值的都是真值&#xff1b; 假值是什么意思呢&#xff1f;就是转换为布尔值都是false&#xff0c;反则就是true 例如&#xff1a; console.log(Boole…

论文阅读:矩阵乘法GEMM的cache优化,子矩阵的切分方法Anatomy of High-Performance MatrixMultiplication

矩阵乘法优化的知名论文goto paper&#xff1a; 矩阵乘法的优化需要将矩阵切分成子矩阵&#xff0c;用子矩阵相乘的结果组合为原矩阵相乘的结果&#xff1a; 上图是拆分矩阵的方法&#xff0c;M表示矩阵&#xff0c;X方向和Y方向的两个维度都是未知的。P表示横条或竖条&#x…

微信小程序使用ECharts的示例详解

目录 安装 ECharts 组件使用 ECharts 组件图表延迟加载 echarts-for-weixin 是 ECharts 官方维护的一个开源项目&#xff0c;提供了一个微信小程序组件&#xff08;Component&#xff09;&#xff0c;我们可以通过这个组件在微信小程序中使用 ECharts 绘制图表。 echarts-fo…

数据分享|R语言用lme4多层次(混合效应)广义线性模型(GLM),逻辑回归分析教育留级调查数据...

全文链接:http://tecdat.cn/?p22813 本教程为读者提供了使用频率学派的广义线性模型&#xff08;GLM&#xff09;的基本介绍。具体来说&#xff0c;本教程重点介绍逻辑回归在二元结果和计数/比例结果情况下的使用&#xff0c;以及模型评估的方法&#xff08;点击文末“阅读原文…

selenuimecharts——可视化分析csdn新星赛道选手展示头像、展示ip城市和断言参赛信息的有效性(进阶篇)

文章目录 ⭐前言⭐selenuim打开赛道报名界面获取新星赛道选手主页&#x1f496; 获取参赛选手主页思路分析&#x1f496; selenuim获取参数选手代码块&#x1f496; selenuim获取参数选手主页城市&#x1f496;echarts分析选手参数信息断言参赛信息的有效性&#xff1a; ⭐结束…

【技术面试】Java八股文业余选手-下篇(持续更新)

文章目录 5. RocketMQ 消息中间件、RabbitMQ、ActiveMQ【√】5.1 RocketMQ 6. Kafka 大数据量消息中间件、ElasticSearch、ZooKeeper【√】6.1 Kafka【√】6.2 ElasticSearch 7. 分布式、研发提效、高并发、线程安全【√】7.1 分布式与集群【√】7.2 高并发、线程安全【】7.3 研…

【数学建模】为什么存在最优策略?

一、说明 在进行优化回归过程&#xff0c;首先要看看是否存在最优策略&#xff1f; 在有限马尔可夫决策过程 &#xff08;MDP&#xff09; 中&#xff0c;最优策略被定义为同时最大化所有状态值的策略。换句话说&#xff0c;如果存在最优策略&#xff0c;则最大化状态 s 值的策…

PyTorch常用代码段汇总

本文是PyTorch常用代码段合集&#xff0c;涵盖基本配置、张量处理、模型定义与操作、数据处理、模型训练与测试等5个方面&#xff0c;还给出了多个值得注意的Tips&#xff0c;内容非常全面。 PyTorch最好的资料是官方文档。本文是PyTorch常用代码段&#xff0c;在参考资料[1](张…

【AutoSAR 架构介绍】

AutoSAR简介 AUTOSAR是Automotive Open System Architecture&#xff08;汽车开放系统架构&#xff09;的首字母缩写&#xff0c;是一家致力于制定汽车电子软件标准的联盟。 AUTOSAR是由全球汽车制造商、部件供应商及其他电子、半导体和软件系统公司联合建立&#xff0c;各成…

ubuntu 静态IP设置

ubuntu 静态IP设置&#xff1a; 1.输入&#xff1a; sudo vim /etc/netplan/01-network-manager-all.yaml Let NetworkManager manage all devices on this system network: ethernets: ens33: dhcp4: no addresses: [192.168.1.119/24] gateway4: 192.168.1.1 nameservers: …

代码随想录额外题目| 数组02 ●189旋转数组 ●724寻找数组中心索引

#189旋转数组 很快写出来但是用了个新数组&#xff0c;不好 void rotate(vector<int>& nums, int k) {vector<int> res(nums.size(),0);for(int i0;i<nums.size();i){int newiik;if(newi>nums.size()-1) newinewi%nums.size();res[newi]nums[i];}numsr…

结构型设计模式之桥接模式【设计模式系列】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythi…

Vue3状态管理库Pinia——核心概念(Store、State、Getter、Action)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

行为型模式 - 迭代器模式

概述 定义&#xff1a; 提供一个对象来顺序访问聚合对象中的一系列数据&#xff0c;而不暴露聚合对象的内部表示。 结构 迭代器模式主要包含以下角色&#xff1a; 抽象聚合&#xff08;Aggregate&#xff09;角色&#xff1a;定义存储、添加、删除聚合元素以及创建迭代器对象…

Mind+积木编程控制小水泵给宠物喂水

前期用scratch&#xff0c;带着小朋友做了大鱼吃小鱼、桌面弹球、小学生计算器3个作品&#xff0c;小朋友收获不小。关键是小家伙感兴趣&#xff0c;做出来后给家人炫耀了一圈后&#xff0c;兴趣大增&#xff0c;嚷嚷着要做更好玩的。 最近&#xff0c;娃妈从抖音上买了个小猫喝…

JMeter 配置环境变量步骤

通过给 JMeter 配置环境变量&#xff0c;可以快捷的打开 JMeter&#xff1a; 打开终端。执行 jmeter。 配置环境变量的方法如下。 Mac 和 Linux 系统 1、在 ~/.bashrc 中加如下内容&#xff1a; export JMETER_HOMEJMeter所在目录 export PATH$JAVA_HOME/bin:$PATH:.:$JME…

pytorch安装GPU版本 (Cuda12.1)教程: Windows、Mac和Linux系统下GPU版PyTorch(CUDA 12.1)快速安装

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

【单调栈 +前缀和】AcWing 4738. 快乐子数组

原题链接 原题链接 相关算法概念介绍 前缀和&#xff08;Prefix Sum&#xff09; 前缀和是指将数组中从开头位置到当前位置的所有元素累加得到的新数组。通常&#xff0c;我们使用一个额外的数组来保存这些累加和&#xff0c;这个数组被称为前缀和数组。对于原始数组A&…

Appium+python自动化(十七)- - Monkey

1、Monkey简介 在Android的官方自动化测试领域有一只非常著名的“猴子”叫Monkey&#xff0c;这只“猴子”一旦启动&#xff0c;就会让被测的Android应用程序像猴子一样活蹦乱跳&#xff0c;到处乱跑。人们常用这只“猴子”来对被测程序进行压力测试&#xff0c;检查和评估被测…