异步编程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 = 线程池 + 优先队列 ,让你 先做完的先拿走,写并行流水线最舒服。

相关推荐
Ivanqhz15 分钟前
正余弦位置编码(Sinusoidal Positional Encoding)
java·linux·数据库
BD_Marathon29 分钟前
消息对象中字段的说明
java·前端·python
zlpzlpzyd40 分钟前
nacos的openapi地址
java
落魄实习生2 小时前
Agent Scope Java 2.x 系列【10】Middleware
java·开发语言·ai
ZealSinger2 小时前
Spring7 RestTemplate弃用迁移
java·spring·后端开发·restclient
朝朝辞暮i3 小时前
C++ 第 13 课:值传递 —— 为什么函数里改了,外面却没变?
java·c++·算法
弹简特3 小时前
【Java项目-企悦抽】16-抽奖模块01-获取活动完整信息接口实现
java·开发语言·状态模式·springboot
泡茶喝茶写代码3 小时前
A股量化数据工程:从 REST 接口到策略信号(第 1 篇):指数列表与实时行情接入
java·python·股票数据api·股票数据·股票数据api接口·股票api数据接口·股票量化数据接口
Sarvartha3 小时前
接口基础知识
java·开发语言
不才不才不不才4 小时前
Spring 源码系列(29): 20 道高频面试题源码级解析合集
java·后端·spring