返回顶部
首页 > 资讯 > 精选 >如何理解Java多线程CompletionService
  • 703
分享到

如何理解Java多线程CompletionService

2023-06-25 11:06:13 703人浏览 独家记忆
摘要

这篇文章主要介绍“如何理解Java多线程CompletionService”,在日常操作中,相信很多人在如何理解Java多线程CompletionService问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如

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

1 CompletionService介绍

CompletionService用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象。
如果你向Executor提交了一个批处理任务,并且希望在它们完成后获得结果。为此你可以将每个任务的Future保存进一个集合,然后循环这个集合调用Futureget()取出数据。幸运的是CompletionService帮你做了这件事情。
CompletionService整合了ExecutorBlockingQueue的功能。你可以将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<Future<V>>();    }

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

然后看一下 completionService.submit 方法:

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

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

来看一下该方法:

 public void run() { //判断执行状态,保证callable任务只被运行一次    if (state != NEW ||        !UNSAFE.compareAndSwapObject(this, runnerOffset,                                     null, Thread.currentThread()))        return;    try {        Callable<V> 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) 处理执行结果:

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

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

QueueingFuture的源码如下:

    private class QueueingFuture extends FutureTask<Void> {        QueueingFuture(RunnableFuture<V> task) {            super(task, null);            this.task = task;        }        protected void done() { completionQueue.add(task); }        private final Future<V> task;    }

3 CompletionService实现任务

public class CompletionServiceTest {    public static void main(String[] args) {        ExecutorService threadPool = Executors.newFixedThreadPool(10);        CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool);        for (int i = 1; i <=10; i++) {            final int seq = i;            completionService.submit(new Callable<Integer>() {                @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”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 如何理解Java多线程CompletionService

本文链接: https://lsjlt.com/news/304180.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何理解Java多线程CompletionService
    这篇文章主要介绍“如何理解Java多线程CompletionService”,在日常操作中,相信很多人在如何理解Java多线程CompletionService问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如...
    99+
    2023-06-25
  • Java多线程 CompletionService
    目录1 CompletionService介绍2 CompletionService源码分析3 CompletionService实现任务4 CompletionService总结1...
    99+
    2024-04-02
  • 如何去理解Java多线程
    如何去理解Java多线程,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1、带着疑问看图1)竞争对象的锁和竞争CPU资源以及竞争被唤醒2)何种情况下获取到了锁,何...
    99+
    2023-06-17
  • 如何理解JAVA的多线程
    这篇文章主要介绍“如何理解JAVA的多线程”,在日常操作中,相信很多人在如何理解JAVA的多线程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解JAVA的多线程”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-06-02
  • Java多线程深入理解
    目录线程Thread类Runnable接口创建线程Thread和Runnable的区别匿名内部类方式实现线程的创建线程安全线程安全线程同步同步方法Lock锁线程状态等待唤醒机制线程间...
    99+
    2024-04-02
  • Java多线程怎么理解
    本文小编为大家详细介绍“Java多线程怎么理解”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java多线程怎么理解”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1 线程池的优势总体来说,线程池有如下的优势:(1...
    99+
    2023-07-05
  • java多线程死锁如何解决
    Java中死锁的解决办法有以下几种:1. 避免使用多个锁:当多个线程需要获取多个锁时,可以尝试将多个锁合并为一个锁,或者将一个锁拆分...
    99+
    2023-08-24
    java
  • Java多线程 ThreadLocal原理解析
    目录1、什么是ThreadLocal变量2、ThreadLocal实现原理3、内存泄漏问题4、使用场景1)存储用户Session2)解决线程安全的问题3)使用ThreadLocal重...
    99+
    2024-04-02
  • 如何理解MySQL多线程复制
    这篇文章给大家介绍如何理解MySQL多线程复制,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Enhanced Multi-threaded Slaves首...
    99+
    2024-04-02
  • 如何深入理解Java多线程与并发框中线程的状态
    本篇文章给大家分享的是有关如何深入理解Java多线程与并发框中线程的状态,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1. 新建状态(New)万事万物都不是凭空出现的,线程也一...
    99+
    2023-06-05
  • 理解Java多线程之并发编程
    目录1 多线程的使用场景2 多线程的缺点2.1 上下文切换的开销(1)上下文切换的开销(2)如何减少上下文切换2.2 多线程中的数据一致性问题(1)线程中访问外部数据的过程(2)线程...
    99+
    2023-02-02
    Java并发编程 java并发编程实战 java并发编程的艺术
  • Java+Linux内核源码之如何理解多线程之进程
    这篇文章主要讲解了“Java+Linux内核源码之如何理解多线程之进程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java+Linux内核源码之如何理解多线程之进程”吧!Linux 内核如...
    99+
    2023-06-15
  • java多线程如何实现
    java实现多线程的方法:(推荐:java视频教程)方式一:继承Thread类的方式创建一个继承于Thread类的子类重写Thread类中的run():将此线程要执行的操作声明在run()创建Thread的子类的对象调用此对象的start(...
    99+
    2022-02-13
    java
  • java如何实现多线程
    Java多线程是Java高级特性之一,通过多线程,我们可以实现多任务同时协同工作,在一定情况下提升程序效率,但是Java多线程仍要慎重使用。 (推荐学习:java课程)首先第一点,Java多线程需要较高的编码技巧,一...
    99+
    2019-06-27
    java教程 java
  • Java如何实现多线程、线程同步
    这篇文章主要介绍了Java如何实现多线程、线程同步的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java如何实现多线程、线程同步文章都会有所收获,下面我们一起来看看吧。1 多线程1.1 进程进程:是正在运行的程...
    99+
    2023-06-30
  • Java多线程之深入理解ReentrantLock
    目录前言一、可重入锁二、ReentrantLock2.1 ReentrantLock的简单使用2.2 ReentrantLock UML图2.3 lock()方法调用链三、AQS3....
    99+
    2024-04-02
  • Java通过卖票理解多线程
            以卖票的例子来介绍多线程和资源共享,下面我们来看看为什么要用卖票作为例子。  卖票是包含一系列动作的过程,有各种操作,例如查询票、收钱、数钱、出...
    99+
    2023-05-31
    java 多线程 卖票
  • 如何解决Java多线程死锁问题
    死锁问题 死锁定义 多线程编程中,因为抢占资源造成了线程无限等待的情况,此情况称为死锁。 死锁举例 注意:线程和锁的关系是:一个线程可以拥有多把锁,一个锁只能被一个线程拥有。 当两个...
    99+
    2024-04-02
  • java多线程并发问题如何解决
    在Java中,可以使用以下方法来解决多线程并发问题:1. 使用synchronized关键字:可以通过在方法或代码块前加上synch...
    99+
    2023-09-27
    java
  • Java多线程编程如何使用
    本篇内容主要讲解“Java多线程编程如何使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java多线程编程如何使用”吧!Process和Thread程序是指令和数据的有序集合, 本身没有运行的...
    99+
    2023-06-22
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作