千家信息网

如何理解Java多线程CompletionService

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要介绍"如何理解Java多线程CompletionService",在日常操作中,相信很多人在如何理解Java多线程CompletionService问题上存在疑惑,小编查阅了各式资料,整理
千家信息网最后更新 2026年11月03日如何理解Java多线程CompletionService

这篇文章主要介绍"如何理解Java多线程CompletionService",在日常操作中,相信很多人在如何理解Java多线程CompletionService问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何理解Java多线程CompletionService"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1 CompletionService介绍

CompletionService用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象。
如果你向Executor提交了一个批处理任务,并且希望在它们完成后获得结果。为此你可以将每个任务的Future保存进一个集合,然后循环这个集合调用Future的get()取出数据。幸运的是CompletionService帮你做了这件事情。
CompletionService整合了Executor和BlockingQueue的功能。你可以将Callable任务提交给它去执行,然后使用类似于队列中的take和poll方法,在结果完整可用时获得这个结果,像一个打包的Future。
CompletionService的take返回的future是哪个先完成就先返回哪一个,而不是根据提交顺序。

2 CompletionService源码分析

首先看一下 构造方法:

   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>();    }

构造法方法主要初始化了一个阻塞队列,用来存储已完成的task任务。

然后看一下 completionService.submit 方法:

public Future submit(Callable task) {        if (task == null) throw new NullPointerException();        RunnableFuture f = newTaskFor(task);        executor.execute(new QueueingFuture(f));        return f;    }    public Future submit(Runnable task, V result) {        if (task == null) throw new NullPointerException();        RunnableFuture f = newTaskFor(task, result);        executor.execute(new QueueingFuture(f));        return f;    }

可以看到,callable任务被包装成QueueingFuture,而 QueueingFuture是 FutureTask的子类,所以最终执行了FutureTask中的run()方法。

来看一下该方法:

 public void run() { //判断执行状态,保证callable任务只被运行一次    if (state != NEW ||        !UNSAFE.compareAndSwapObject(this, runnerOffset,                                     null, Thread.currentThread()))        return;    try {        Callable c = callable;        if (c != null && state == NEW) {            V result;            boolean ran;            try {            //这里回调我们创建的callable对象中的call方法                result = c.call();                ran = true;            } catch (Throwable ex) {                result = null;                ran = false;                setException(ex);            }            if (ran)            //处理执行结果                set(result);        }    } finally {        runner = null;        // state must be re-read after nulling runner to prevent        // leaked interrupts        int s = state;        if (s >= INTERRUPTING)            handlePossibleCancellationInterrupt(s);    }}

可以看到在该 FutureTask 中执行run方法,最终回调自定义的callable中的call方法,执行结束之后,

通过 set(result) 处理执行结果:

/**     * Sets the result of this future to the given value unless     * this future has already been set or has been cancelled.     *     * 

This method is invoked internally by the {@link #run} method * upon successful completion of the computation. * * @param v the value */ protected void set(V v) { if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { outcome = v; UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state finishCompletion(); } }

继续跟进finishCompletion()方法,在该方法中找到 done()方法:

protected void done() { completionQueue.add(task); }

可以看到该方法只做了一件事情,就是将执行结束的task添加到了队列中,只要队列中有元素,我们调用take()方法时就可以获得执行的结果。
到这里就已经清晰了,异步非阻塞获取执行结果的实现原理其实就是通过队列来实现的,FutureTask将执行结果放到队列中,先进先出,线程执行结束的顺序就是获取结果的顺序。

CompletionService实际上可以看做是Executor和BlockingQueue的结合体。CompletionService在接收到要执行的任务时,通过类似BlockingQueue的put和take获得任务执行的结果。CompletionService的一个实现是ExecutorCompletionService,ExecutorCompletionService把具体的计算任务交给Executor完成。

在实现上,ExecutorCompletionService在构造函数中会创建一个BlockingQueue(使用的基于链表的无界队列LinkedBlockingQueue),该BlockingQueue的作用是保存Executor执行的结果。当计算完成时,调用FutureTask的done方法。当提交一个任务到ExecutorCompletionService时,首先将任务包装成QueueingFuture,它是FutureTask的一个子类,然后改写FutureTask的done方法,之后把Executor执行的计算结果放入BlockingQueue中。

QueueingFuture的源码如下:

/**     * FutureTask extension to enqueue upon completion     */    private class QueueingFuture extends FutureTask {        QueueingFuture(RunnableFuture task) {            super(task, null);            this.task = task;        }        protected void done() { completionQueue.add(task); }        private final Future task;    }

3 CompletionService实现任务

public class CompletionServiceTest {    public static void main(String[] args) {        ExecutorService threadPool = Executors.newFixedThreadPool(10);        CompletionService completionService = new ExecutorCompletionService(threadPool);        for (int i = 1; i <=10; i++) {            final int seq = i;            completionService.submit(new Callable() {                @Override                public Integer call() throws Exception {                    Thread.sleep(new Random().nextInt(5000));                    return seq;                }            });        }        threadPool.shutdown();        for (int i = 0; i < 10; i++) {            try {                System.out.println(                        completionService.take().get());            } catch (InterruptedException e) {                e.printStackTrace();            } catch (ExecutionException e) {                e.printStackTrace();            }        }    }}

到此,关于"如何理解Java多线程CompletionService"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

方法 任务 结果 队列 线程 学习 就是 顺序 事情 子类 对象 更多 源码 处理 帮助 阻塞 实用 幸运 为此 接下来 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技企业 亿人帮互联网科技有限公司 互联网科技资迅 互联网公司 科技公司 上海互联网科技有限公司 互联网科技公司发展 合肥互联网科技公司 紫鲸互联网科技 迪茉互联网科技 广西互联网科技公司 互联网科技英文翻译 全球顶尖互联网科技公司 重庆互联网医院沙龙医盟信息科技 河南猎农互联网科技有限公司 宜昌元轩互联网科技有限公司 广西互联网科技孵化中心 小米互联网科技园入驻 城市宝互联网科技有限公司 互联网硬科技公司 互联网科技收购价值 广东万易互联网科技有限公司惠州分公司 广州互联网科技公司 银川新华互联网科技学校地址 昊天互联网科技有限公司 互联网媒体平台算高科技产业 合肥互联网科技公司公章图片 江苏互联网智能科技软件 上海创道互联网络科技有限公司 宇信科技在杭州互联网排第几 美国五大互联网科技公司市值多少
0