Java并发——CompletionService

CompletionService使用与源码分析 一、Future&FutureTask 在《Java线程详解》这篇文章中,介绍了创建一个Java线程的三种方式,其中继承Thread类或实现Runnable接口都可以创建线程,但这两种方法都有一个问题就是:没有返回值,不能获取执行完的结果。因此后面在JDK1.5才新增了一个Callable接口来解决上面的问题,而Future和FutureTask就可以与Callable配合起来使用。 而Callable只能在线程池中提交任务使用,且只能在submit()和invokeAnay()以及invokeAl 阅读详情

CompletionService

接口CompletionService的功能是以异步的方式生产新的任务,一边处理已完成任务的结果,这样可以将执行任务与处理任务分离开来进行处理。使用submit执行任务,使用take取得已完成的任务,并按照完成这些任务的时间顺序处理它们的结果。

接口 Completion Service的结构比较简洁,仅有一个实现类 Executor Completion Service,该类的构造方法如图所示。
在这里插入图片描述

从构造方法的声明中可以发现,类 Executor Completion Service需要依赖于 Executor对象,大部分的实现也就是使用线程池 ThreadPoolExecutor对象。

take()方法
public class TestDemo {
    public static void main(String[] args) {
        try {
            //take:获取并移除下一个已完成任务的Futrue,如果目前不存在这样的任务,则阻塞。
            ExecutorService executorService = Executors.newCachedThreadPool();
            CompletionService cs = new ExecutorCompletionService(executorService);
            for (int i = 0; i < 10; i++) {
                cs.submit(new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        long sleepValue = (int)(Math.random() * 1000);
                        System.out.println("sleep=" + sleepValue + " " + Thread.currentThread().getName());
                        Thread.sleep(sleepValue);
                        return "返回值:" + sleepValue + " " + Thread.currentThread().getName();
                    }
                });
            }
            for (int i = 0; i < 10; i++) {
                System.out.println(cs.take().get());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

从运行结果来看,方法 take()是按任务执行的速度,从快到慢的顺序获得Future对象,因为打印的时间是从小到大。

sleep=738 pool-1-thread-1
sleep=911 pool-1-thread-8
sleep=467 pool-1-thread-10
sleep=407 pool-1-thread-7
sleep=131 pool-1-thread-3
sleep=79 pool-1-thread-6
sleep=563 pool-1-thread-4
sleep=869 pool-1-thread-5
sleep=545 pool-1-thread-2
sleep=551 pool-1-thread-9
返回值:79 pool-1-thread-6
返回值:131 pool-1-thread-3
返回值:407 pool-1-thread-7
返回值:467 pool-1-thread-10
返回值:545 pool-1-thread-2
返回值:551 pool-1-thread-9
返回值:563 pool-1-thread-4
返回值:738 pool-1-thread-1
返回值:869 pool-1-thread-5
返回值:911 pool-1-thread-8
poll()方法

方法poll()的作用是获取并移除表示下一个已完成任务的 Future,如果不存在这样的任务,则返回null,方法pol()无阻
塞的效果:

public class TestDemo2 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        CompletionService cs = new ExecutorCompletionService(executorService);
        for (int i = 0; i < 1; i++) {
            cs.submit(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    Thread.sleep(3000);
                    System.out.println("3秒过后");
                    return "返回值";
                }
            });
        }
        for (int i = 0; i < 1; i++) {
            System.out.println(cs.poll());
        }
    }
}

poll()方法返回null,因为当前没有任何已完成任务的Future对象,所以返回为null。poll()方法不具有阻塞特性。
在这里插入图片描述

poll(long timeout, TimeUnit unit)

方法Future pol(long timeout, TimeUnit unit)的作用是等待指定的timeout时间,在timeout时间之内获取到值时立即向下继续执行,如果超时也立即向下执行。

public class TestDemo3 {
    public static void main(String[] args) {
        try {
            MyCallableA a =  new MyCallableA();
            MyCallableB b = new MyCallableB();

            Executor executor = Executors.newSingleThreadExecutor();
            CompletionService cs = new ExecutorCompletionService(executor);
            cs.submit(a);
            cs.submit(b);

            for (int i = 0; i < 2; i++) {
                System.out.println("zzzzzzzzzzz" + " " + cs.take());
            }
            System.out.println("main end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class MyCallableA implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("MyCallableA begin " + System.currentTimeMillis());
        Thread.sleep(1000);
        System.out.println("MyCallableA end " + System.currentTimeMillis());
        return "returnA";
    }
}

class MyCallableB implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("MyCallableB begin " + System.currentTimeMillis());
        Thread.sleep(5000);
        int i = 0;
        if (i == 0) {
            throw new Exception("抛出异常!");
        }
        System.out.println("MyCallableB end " + System.currentTimeMillis());
        return "returnB";
    }
}

MyCallableB虽然出现异常,但是并没有调用FutureTask的get()方法,所以不出现异常。
在这里插入图片描述

调用get()方法:
在这里插入图片描述
在这里插入图片描述

调换A和B的执行顺序:
在这里插入图片描述
任务B出现异常,任务A并未输出。
在这里插入图片描述

调用poll()方法:

public class TestDemo3 {
    public static void main(String[] args) {
        try {
            MyCallableA a =  new MyCallableA();
            MyCallableB b = new MyCallableB();

            Executor executor = Executors.newSingleThreadExecutor();
            CompletionService cs = new ExecutorCompletionService(executor);
            cs.submit(a);
            cs.submit(b);

            for (int i = 0; i < 2; i++) {
                System.out.println("zzzzzzzzzzz" + " " + cs.poll());
            }
            Thread.sleep(6000);
            System.out.println("A处" + " " + cs.poll());
            System.out.println("B处" + " " + cs.poll());
            System.out.println("main end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class MyCallableA implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("MyCallableA begin " + System.currentTimeMillis());
        Thread.sleep(1000);
        System.out.println("MyCallableA end " + System.currentTimeMillis());
        return "returnA";
    }
}

class MyCallableB implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("MyCallableB begin " + System.currentTimeMillis());
        Thread.sleep(5000);
        int i = 0;
        if (i == 0) {
            throw new Exception("抛出异常!");
        }
        System.out.println("MyCallableB end " + System.currentTimeMillis());
        return "returnB";
    }
}

任务B出现异常后,poll()返回值为null
在这里插入图片描述

poll()后调用get()方法获取返回值:
在这里插入图片描述
A任务返回值正常,任务B返回值出现异常。
在这里插入图片描述

调换A和B任务执行顺序:
在这里插入图片描述
任务A并未打印,任务B抛出异常。
在这里插入图片描述

Future submit(Runnable task, V result)
public class TestDemo4 {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo();
        MyRunnable5 myRunnable5 = new MyRunnable5(userInfo);

        Executor executor = Executors.newCachedThreadPool();
        CompletionService cs = new ExecutorCompletionService(executor);
        Future<UserInfo> future = cs.submit(myRunnable5, userInfo);
        try {
            System.out.println(future.get().getUsername() + " " + future.get().getPassword());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class UserInfo {
    private String username;
    private String password;

    public UserInfo() {
        super();
    }

    public UserInfo(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}


class MyRunnable5 implements Runnable {
    private UserInfo userInfo;

    public MyRunnable5(UserInfo userInfo) {
        this.userInfo = userInfo;
    }

    @Override
    public void run() {
        userInfo.setUsername("usernameValue");
        userInfo.setPassword("passwordValue");
        System.out.println("run运行了 ");
    }
}

在这里插入图片描述

总结

接口CompletionService完全可以避免FutureTask类阻塞的缺点,可更加有效地处理Future的返回值,也就是哪个任务先执行完,CompletionService 就先取得这个任务的返回值再处理。

CompletableFuture中的CompletionException异常真是坑到我了! 复制代码。 阅读详情

相关推荐

java并发编程之CompletionService

应用场景当向Executor提交多个任务并且希望获得它们在完成之后的结果,如果用FutureTask,可以循环获取task,并调用get方法去获取task执行结果,但是如果task还未完成,获取结果的线程将阻塞直到task完成,由于不知道哪个task优先执行完毕,使用这种方式效率不会很高。在jdk5时候提出接口CompletionService,它整合了Executor和BlockingQueue的

u010185262的博客 5761

CompletionService详解

当我们有批量执行多个异步任务的业务,并且需要调用get()获取执行结果的时候,我们写的代码一般如下: Future f1 = excutor.submit(c1); f1.get(); Future f2 = excutor.submit(c2); f2.get(); f1.get()在获取成功之前会被阻塞,会阻塞c2的执行,严重降低了效率。 这时我们可以通过CompletionService来解决这一问题! CompletionService结构 CompletionSerive接口有一个实现类Exe

qq_40276626的博客 7224

Java并发CompletionService

一.简介 CompletionService的应用场景:批量提交异步任务。 CompletionService将线程池Executor和阻塞队列BlockingQueue融合在一起,使得批量异步任务的管理更简单。 CompletionService能够让异步任务的执行结果有序化,先执行完的先进入阻塞队列,避免无谓的等待。 二.API 接口 public interface CompletionService<V> { // 提交Callable类型的任务 Future<V>

独立开发,substack顶级编辑 713

异步编程(CompletableFuture、CompleteService)

并发

weixin_41998947的博客 2159

MYSQL、ORACLE、PostgreSQL数据库对象层次及权限管理对比

本文为出于自己扩展、比较、图形化的思维路径自行总结归纳,可能有些细节不太准确,欢迎指正。MySQL、Oracle、PostgreSQL关系型数据库都有管理员用户、用户、权限管理、表函数索引等数据库对象,schema。但在数据库对象隶属层次上有差异和相同的地方。

rachel_2016的博客 1489

强网杯Web题ezphp解题全记录:利用PHP反序列化与条件竞争拿下服务器

本文详细解析了强网杯Web题目ezphp的解题过程,通过PHP反序列化与条件竞争漏洞的组合利用,成功获取服务器权限。文章深入剖析了反序列化链的构造、文件上传绕过技巧以及条件竞争的实际应用,为CTF选手和Web安全研究者提供了宝贵的实战经验。

weixin_29006187的博客 375

CompletionService的基本使用以及原理

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

qq_39939541的博客 2468

1 FFmpeg从入门到精通-FFmpeg简介

1.FFmpeg简介 1.1 FFmpeg的定义 1.2 FFmpeg的历史 1.3 FFmpeg的基本组成 1.4 FFmpeg的编解码工具ffmpeg 1.5 FFmpeg的播放器ffplay 1.6 FFmpeg的多媒体分析器ffprobe 1.7 FFmpeg编译(1)FFmpeg之Windows平台编译(2)FFmpeg之Linux平台编译(3)FFmpeg之OS X平台编译 1.8 FFmpeg编码支持与定制(1)FFmpeg的编码器支持(2)FFmpe

migu123的专栏 3687

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

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

rhwayfun专栏 1万+

11、Windows Autopilot 部署与设备注册全攻略

本文详细介绍了Windows Autopilot的完整部署流程,涵盖注册配置文件设置、注册状态页面(ESP)配置、设备注册方法(包括CSV导入、JSON注入、在线注册等)、自动化脚本实现及故障排除技巧。通过手动与PowerShell自动化两种方式指导用户完成配置,并提供流程图、最佳实践和常见问题解答,帮助IT管理员高效实现设备零接触部署与管理。

ii567的博客 342

多智能体记忆架构设计:从分层模型到一致性实践

多智能体记忆架构本质上是一个有状态、分布式、支持遗忘的知识系统。从分层模型入手,结合RBAC隔离、版本向量一致性以及混合存储,可以构建出既灵活又健壮的生产级方案。可微分记忆:让记忆的读写操作嵌入端到端训练。基于大模型的记忆压缩:用LLM自动生成情景摘要,取代规则式遗忘。联邦记忆:不同组织之间的多智能体系统在不共享原始数据的情况下协同记忆。希望本文能为你的多智能体项目提供一块坚实的基石。欢迎在评论区分享你在实践中遇到的记忆架构难题。

Ven%的博客 169

java高并发之CompletionService优化多线程并发

1:还是上个需求 工作流策略的一个节点,需要查询13个第三方的数据,并返回查询结果变量,由于时间的要求,必须实现并行查询,而且要求13个查询全部完成才能返回工作流节点。 没看过上个帖子的可以看看 java高并发之有返回值的多线程并发 上一个帖子的实现是 执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了

lichch的博客 2165

基于物联网的门禁与考勤系统(阿里云)_81

本课题设计的基于物联网的门禁与考勤管理系统,结合现代信息技术,利用指纹识别、射频卡、密码输入和远程控制等多种开锁方式,提升门禁系统的安全性和灵活性;同时,通过物联网平台进行数据上传和远程管理,极大提高了管理效率。通过智能化的考勤功能,系统可以实时记录员工的出入情况,并通过云平台进行远程查询和管理,推动门禁与考勤管理的数字化、智能化和高效化。

1万+

Java高并发编程中CompletionService的使用及详细介绍-刘宇

作者:刘宇。一、什么是CompletionService?二、ExecutorCompletionService中的方法1、构造方法2、submit方法3、take方法4、poll方法三、案例1、问题复现2、利用CompletionService解决问题一、什么是CompletionService?它是Java8的新增接口,它的实现类是ExecutorCompletionService。CompletionService会根据线程池中Task的执行结果按执行完成的先后顺序排序,任务先完成的可优先获取到。

刘宇的博客 9316

大模型之Spring AI实战系列(二十六):Spring Boot + DeepSeek 实战指南:构建AI聊天应用

在人工智能技术飞速发展的今天,大型语言模型已经成为了推动技术创新的重要力量。DeepSeek作为国内领先的大型语言模型提供商,其推出的DeepSeek系列模型在多个领域都展现出了卓越的性能。本文将详细介绍如何使用Spring Boot框架集成DeepSeek API,构建一个简单的AI聊天应用。我们将实现两个核心功能:普通文本生成和流式文本生成。

寻道AI,探索AI无限可能! 2257

YOLOv8 骨骼结构识别详细说明

YOLOv8骨骼结构识别是一种基于深度学习技术的医学影像分析方法,主要用于X光、CT等影像中的骨骼定位与识别。该系统具有多骨骼同步识别能力,可应用于手部、脊柱、骨盆等不同部位,并能精确定位骨骼关键点。技术实现包括数据预处理、模型训练、推理检测、关键点分析和批量处理五个核心模块,支持骨折检测、骨龄评估等临床应用。该系统需注意医学合规性,要求高质量标注数据,并针对骨骼影像特点进行特征工程优化,同时考虑不同设备的部署需求。

u010117029的博客 330

【Java并发】- 使用CompletionService异步收集任务结果

概述 在使用Executor或者直接使用ExecutorService的时候,通常会提交很多个任务同时还需要等待任务的返回结果,这个时候如何快速的回收任务的结果就成了问题。 而使用CompletionService可以生产新的异步任务与使用已完成任务的结果分离开来。比如前端页面的图片这种IO的任务,我们并不关心图片的顺序,只是希望能尽快的将图片展示出来。这个时候如果只是顺序的去取图片结果的话,

LightOfMiracle的博客 1464

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Java并发编程-Executor框架之CompletionService

在前面我们已经学习过Executor框架之Callable和Future接口,我们知道利用list保存submit的callable任务所返回的Future对象。再在主线程中遍历这个list并调用Future的get()方法取到任务的返回值进行处理。Java通过另一个类CompletionService进行改进。两者最主要的区别在于submit的任务不一定是按照加入自己维护的list顺序完成的。从l

记忆力不好的博客 4520

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java并发类API——CompletionService

CompletionService 是 Java 中 java.util.concurrent 包的一部分,用于管理并发任务的执行,并以完成的顺序提供结果。它结合了线程池和阻塞队列的功能,用于提交任务并按照任务完成的顺序来检索结果,而不是按照任务提交的顺序。接口CompletionService的功能是以异步的方式一边生产新的任务,一边处理已完成任务的结果,这样可以将执行任务与处理任务分离开来进行处理。使用submit执行任务,使用take取得已完成的任务,并按照完成这些任务的时间顺序处理它们的结果。

sinat_33536503的博客 1276

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

java并发之CompletionService

本文介绍了如何通过阻塞队列和FutureTask实现任务按完成顺序获取结果的机制。通过使用ExecutorCompletionService,可以将任务提交到线程池中执行,并将完成的Future对象放入阻塞队列中。通过调用take或poll方法,可以从队列中获取已完成的Future,进而通过get方法获取任务结果。文章还提供了一个示例代码,展示了如何异步询价并将结果保存到数据库中。通过分析ExecutorCompletionService的源码,解释了任务完成时如何将Future放入队列,并确保先完成的任务

不愿言弃-念何的博客 536

java并发编程(五)CompletionService

CompletionService可以在多个任务中依时间先后获取最先执行完成的任务结果。废话不说,直接上代码。 import java.util.concurrent.Callable; public class BlockCall extends Thread implements Callable<String>{ private int blocktime; publi...

pengdayong77的博客 167

CompletionService:Java并发工具包

摘要:CompletionService是Java并发编程中解决"队头阻塞"问题的利器,它通过将任务执行与结果消费解耦,实现按任务完成顺序获取结果。其核心组件ExecutorCompletionService采用装饰器模式,利用QueueingFuture包装任务,在FutureTask的done()钩子方法中实现结果自动入队。相比传统ExecutorService需要手动管理Future集合,CompletionService内置并发安全的结果队列,特别适合批量异步任务处理场景。通过分

源码获取 | 运行部署 | 定制二开修改,如果回复不及时请耐心等待,请见谅。 739

java future用法_Java并发系列(10)——FutureTask 和 CompletionService

接上一篇《Java并发系列(9)——并发工具类》8 FutureTask 与 CompletionService把 FutureTask 和 CompletionService 放在一起,并不是因为它们之间有什么特别的联系,虽然确实有一点联系。主要是因为下一章要讲线程池,如果不把 FutureTask 和 CompletionService 搞清楚,线程池的部分代码看得会比较困惑。8.1 F...

weixin_39582724的博客 188

java线程池批量提交任务,Java并发专题 带返回结果的批量任务运行 CompletionService ExecutorService.invokeAll...

转载请标明出处:http://blog.youkuaiyun.com/lmj623565791/article/details/27250059普通情况下,我们使用Runnable作为主要的任务表示形式,可是Runnable是一种有非常大局限的抽象,run方法中仅仅能记录日志,打印,或者把数据汇总入某个容器(一方面内存消耗大,还有一方面须要控制同步,效率非常大的限制),总之不能返回运行的结果;比方同一时候10...

weixin_42622428的博客 1206

JAVA并发编程学习20(CompletionService示例)

CompletionService提供了一个线程池执行结果的队列,其中的任务任务执行结果按照任务执行完毕的先后顺序排列放置。示例代码如下: public class MyTest { public static void main(String[] args) throws Exception { ExecutorService executorService = new ThreadPoolExecutor(4,10,10, TimeUnit.SECONDS,n.

qq_32852017的博客 240

java并发 CompletionService (八)

一、CompletionService的实现类:ExecutorCompletionService        相当于ExecutorService与BlockingQueue的组合,即能够将一组任务的运行结果按结果的先后顺序放入阻        塞队列中,以便逐一取出   二、适用场景:       假定有针对某个问题的一组求解程序,每个求解程序都能返回某种类型的 Result ...

令狐冲的专栏 152
上一篇: Java并发——Future和Callable
下一篇: Java并发——ScheduledExecutorService
吴声子夜歌
博客等级 码龄9年 2687粉丝 2261原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值