异步编程CompletionService

CompletionService 是 Java 并发包(java.util.concurrent)里的一个 "异步结果收割机"

它把「提交任务」和「拿结果」两件事解耦:

你只管往里扔任务;它帮你盯着谁先跑完,让你 按完成顺序 取结果,而不是按提交顺序。


一、核心 API(就 4 个常用方法)

方法 作用
submit(Callable/Runnable) 扔一个任务进去
take() 阻塞 直到有任务完成,返回完成的 Future
poll() 立刻返回,如果没有已完成的任务返回 null
poll(timeout, unit) 等指定时间,超时返回 null

二、使用套路(3 步曲)

  1. 创建线程池 + CompletionServic

    复制代码
    ExecutorService pool = Executors.newFixedThreadPool(4);
    CompletionService<String> cs = new ExecutorCompletionService<>(pool);
  2. 批量提

    复制代码
    for (int i = 0; i < 10; i++) {
        final int no = i;
        cs.submit(() -> {
            Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 3000));
            return "task-" + no;
        });
    }
  3. 按完成顺序收割

    复制代码
    for (int i = 0; i < 10; i++) {
        String result = cs.take().get();   // 谁先跑完谁先拿到
        System.out.println(result);
    }
    pool.shutdown();

三、场景举例

  • 并发下载:10 张图片同时开线程下,下好一张立刻显示一张,不用等全部下完。

  • 并发调用多服务:A、B、C 三个微服务都查一遍,谁返回快就用谁的数据。

  • 并行计算:跑 100 个 Monte-Carlo 任务,每算完一个就汇总,不用等全部结束再统计。


四、对比"裸用 FutureList"

方式 拿结果顺序 是否阻塞
List<Future> 按提交顺序 会卡在还没跑完的任务
CompletionService 按完成顺序 只阻塞在 take(),总有结果就返回

五、完整可运行 Demo

复制代码
import java.util.concurrent.*;
public class Demo {
    public static void main(String[] args) throws Exception {
        ExecutorService pool = Executors.newFixedThreadPool(4);
        CompletionService<Integer> cs = new ExecutorCompletionService<>(pool);

        // 1. 提交 5 个耗时不一样的任务
        for (int i = 1; i <= 5; i++) {
            final int sec = i;
            cs.submit(() -> {
                TimeUnit.SECONDS.sleep(sec);
                return sec;
            });
        }

        // 2. 按完成顺序打印
        for (int i = 0; i < 5; i++) {
            Integer who = cs.take().get();
            System.out.println("任务 " + who + " 秒完成!");
        }
        pool.shutdown();
    }
}

运行结果(每次都一样):

任务 1 秒完成!

任务 2 秒完成!

任务 3 秒完成!

任务 4 秒完成!

任务 5 秒完成!


一句话总结:
CompletionService = 线程池 + 优先队列 ,让你 先做完的先拿走,写并行流水线最舒服。

相关推荐
serendipity_hky12 分钟前
互联网大厂Java面试故事:核心技术栈与场景化业务问题实战解析
java·spring boot·redis·elasticsearch·微服务·消息队列·内容社区
我真不会起名字啊12 分钟前
C、C++中的sprintf和stringstream的使用
java·c语言·c++
十点摆码13 分钟前
Spring Boot2 使用 Flyway 管理数据库版本
java·flyway·数据库脚本·springboo2·数据库脚本自动管理
毕设源码-钟学长31 分钟前
【开题答辩全过程】以 基于Javaweb的电动汽车充电桩管理系统为例,包含答辩的问题和答案
java·spring boot
多敲代码防脱发36 分钟前
为何引入Spring-cloud以及远程调用(RestTemplate)
java·开发语言
毕设源码-邱学长36 分钟前
【开题答辩全过程】以 基于JavaWeb的家庭理财管理系统的设计与实现为例,包含答辩的问题和答案
java
sailing-data1 小时前
【SE】接口标准化
java·开发语言
t***p9351 小时前
idea创建springBoot的五种方式
java
+VX:Fegn08951 小时前
计算机毕业设计|基于springboot+vue的学校课程管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
S***26751 小时前
【监控】spring actuator源码速读
java·spring boot·spring