问题

  • 使用 Future.get()异步获取结果的时候,当异步任务没有计算成功,主线程调用 get()方法获取结果的时候会一直阻塞到线程完成为止,影响运行效率。
  • 我们习惯使用线程池达到线程的复用,线程池中使用 submit 异步计算任务获取返回结果的时候,我们可能 future.get()方式获取任务的返回结果,但是 N 个线程去执行,当前任务没有执行完成,而其他任务执行完事了,我们通过 future.get()方式获取结果的时候即使其他完事了,我们还需要等待这个任务完成,影响效率,我们希望可以这样,谁先完成,谁就可以获取结果,CompleService 就干这个事的。

实现原理

我们一般使用 CompletionService 的子类 ExecutorCompletionService,其内部有一个阻塞队列,传入 N 个任务,任意任务完成之后,会将执行结果放入阻塞队列中,其他线程可以调用 take,poll 方法从阻塞队列中获取任务,任务进出队列遵循先进先出的原则。

例子

 //例子打印结果会是先完成的先打印public static void main(String[] args) throws Exception{//初始化线程池ExecutorService threadPool = Executors.newFixedThreadPool(5);// 同时运行多个任务CompletionService<String> completionService = new ExecutorCompletionService(threadPool);for (int i=0;i<5;i++){completionService.submit(new Callable<String>() {@Overridepublic String call() throws Exception {//线程随机休眠int time=new Random().nextInt(5);TimeUnit.SECONDS.sleep(time);return "当前线程名为 " + Thread.currentThread() + "执行时间" + time + "秒";}});}for (int i = 1; i <= 5; i++) {Future<String> future = completionService.take();System.out.println(future.get());}}

源码

类的继承结构图

CompletionService 类

 public interface CompletionService<V> {//提交一个Callabl类型的任务,并返回关联任务的FutureFuture<V> submit(Callable<V> task);//提交的任务类型为Runable类型,并返回关联任务的FutureFuture<V> submit(Runnable task, V result);//从内部阻塞队列中获取并移除第一个执行的任务,阻塞直到任务完成Future<V> take() throws InterruptedException;//从内部阻塞队列中获取并移除第一个执行完成的任务,这个获取不到会返回,不阻塞Future<V> poll();//从内部阻塞队列中获取并移除第一个执行完成的任务,阻塞时间unit内获取不到就返回Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;}

ExecutorCompletionService

    public class ExecutorCompletionService<V> implements CompletionService<V> {//执行具体的任务private final Executor executor;//封装Callable或Runnable对象private final AbstractExecutorService aes;//队列,用来存放已经完成的任务private final BlockingQueue<Future<V>> completionQueue;//继承FutureTask,线程池的就讲过FutureTask,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;}//构造函数初始化public ExecutorCompletionService(Executor executor) {if (executor == null)throw new NullPointerException();this.executor = executor;//进行类型转化this.aes = (executor instanceof AbstractExecutorService) ?(AbstractExecutorService) executor : null;//初始化化一个LinkedBlockingQueue先进先出阻塞队列this.completionQueue = new LinkedBlockingQueue<Future<V>>();}public Future<V> submit(Callable<V> task) {if (task == null) throw new NullPointerException();RunnableFuture<V> f = newTaskFor(task);//走ThreadPool线程池那套逻辑 ,提交一个任务,再任务完成之后调用上面的Done将自己加入队列中executor.execute(new QueueingFuture(f));return f;}。。。Runnable类型的submit类似}

运行结果

总结

上图可以看到先执行的可以提交获取到,原理其实就是使用了一个阻塞队列存放已经完成任务的结果,应用程序可以从阻塞队列中获取先执行的任务

巨人肩膀

https://cloud.tencent.com/developer/article/1444259
https://blog.csdn.net/jijianshuai/article/details/75480406

并发编程系列-CompleService 类相关推荐

  1. 高并发编程系列:4大并发工具类的功能、原理、以及应用场景

    通常我们所说的并发包也就是java.util.concurrent,集中了Java并发工具类和并发容器等,今天主要介绍Java并发编程的工具类,我先从Java并发工具包谈起. 01 - 并发工具包涵盖 ...

  2. Java 并发编程系列之带你了解多线程

    早期的计算机不包含操作系统,它们从头到尾执行一个程序,这个程序可以访问计算机中的所有资源.在这种情况下,每次都只能运行一个程序,对于昂贵的计算机资源来说是一种严重的浪费. 操作系统出现后,计算机可以运 ...

  3. 高并发编程系列:NIO、BIO、AIO的区别,及NIO的应用和框架选型

    谈到并发编程就不得不提到NIO,以及相关的Java NIO框架Netty等,并且在很多面试中也经常提到NIO和AIO.同步和异步.阻塞和非阻塞等的区别.我先简短介绍下几个NIO相关的概念,然后再谈NI ...

  4. python并发编程之semaphore(信号量)_Python 并发编程系列之多线程

    Python 并发编程系列之多线程 2 创建线程 2.1 函数的方式创建线程 2.2 类的方式创建线程 3 Thread 类的常用属性和方法 3.1 守护线程: Deamon 3.2 join()方法 ...

  5. java 线程钩子_高级并发编程系列六(线程池钩子函数)

    1.考考你 国庆假期快要结束了,准备回到工作岗位的你,是不是已经开始撸起袖子敲代码,反正发完文章我就要准备去加班了,程序员就这样,有干劲对吧 那么来吧,让我们一起分享完高级并发编程系列中,线程池小节的 ...

  6. 并发编程系列之五多线程synchronized是可重复加锁,重入锁

    并发编程系列之五多线程synchronized是可重复加锁,重入锁.对于重入锁的概念就是可以重复的加锁.. 示例1,在同一个类里面进行加锁,不同的方法调用,都一层一层的嵌套进行加锁,示例1演示重入锁的 ...

  7. Java并发编程:Thread类的使用

    为什么80%的码农都做不了架构师?>>>    Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学 ...

  8. Java Review - 并发编程_原子操作类LongAdder LongAccumulator剖析

    文章目录 概述 小Demo 源码分析 重要的方法 long sum() reset sumThenReset longValue() add(long x) longAccumulate(long x ...

  9. reentrantlock非公平锁不会随机挂起线程?_【原创】Java并发编程系列16 | 公平锁与非公平锁...

    本文为何适原创并发编程系列第 16 篇,文末有本系列文章汇总. 上一篇提到重入锁 ReentrantLock 支持两种锁,公平锁与非公平锁.那么这篇文章就来介绍一下公平锁与非公平锁. 为什么需要公平锁 ...

最新文章

  1. oracle锁表语句执行提示无法终止当前对话_显示Oracle数据库表或行上持有锁的所有会话...
  2. 在学习django的时候
  3. java数字转字符串及字符串转数字
  4. 【三代增强干货一枚】外向交货单Delivery (VL01N)Header屏幕增强
  5. 13 | 答疑(一):无法模拟出 RES 中断的问题,怎么办?
  6. 动手Lab|利用CSI和Kubernetes实现动态扩容
  7. 数据科学入门与实战:玩转pandas之一
  8. v4l2驱动框架_【干货分享】Xilinx Linux V4L2视频管道(Video Pipeline)驱动程序分析...
  9. 第15届创新英语大赛初赛第二阶段题目
  10. python整数缓存机制
  11. python中open打开路径问题_Python学习笔记之open()函数打开文件路径报错问题
  12. 类型转换操作符(C++)
  13. 【Qt】仿QQ表情选择控件
  14. SQL函数入门--统计函数+分组函数
  15. ISO镜像转换成docker镜像
  16. 游戏原画是怎样的?加班多么?
  17. tf.nn.xw_plus_b()
  18. 创新案例分享 | 建立医院绩效考核平台,促进医院提质增效
  19. AL11的目录配置和open dataset访问共享文件的权限
  20. 手动实现一个满足promises-aplus-tests的Promise

热门文章

  1. 荣耀8.0系统设备(亲测有效)激活Xposed框架的经验
  2. python课程报告模板_我用Python做了一份PDF报告!!!
  3. 7. Fabric2.2 区块链农产品溯源系统 - 需求分析与方案设计
  4. 计算机第三章ppt课件,计算机英语第三章课件.ppt
  5. Java使用JestClient操作ElasticSearch
  6. Spring Cloud第二季--Spring Cloud Bus
  7. 电子通信类考研的建议
  8. Consider defining a bean of type ‘java.util.List‘ in your configuration.
  9. 价值连城的神站:广西图书馆的电子资源(视频、书、期刊...)
  10. 华为防火墙USG6300轻松4步配置