1、Future

Future模式是多线程设计常用的一种设计模式。Future模式可以理解成:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间之后,我就便可以从Future那儿取出结果。
Future提供了三种功能:
判断任务是否完成
能够中断任务
能够获取任务执行的结果
向线程池中提交任务的submit方法不是阻塞方法,而Future.get方法是一个阻塞方法,当submit提交多个任务时,只有所有任务都完成后,才能使用get按照任务的提交顺序得到返回结果,所以一般需要使用future.isDone先判断任务是否全部执行完成,完成后再使用future.get得到结果。(也可以用get (long timeout, TimeUnit unit)方法可以设置超时时间,防止无限时间的等待)
三段式的编程:1.启动多线程任务2.处理其他事3.收集多线程任务结果,Future虽然可以实现获取异步执行结果的需求,但是它没有提供通知的机制,要么使用阻塞,在future.get()的地方等待future返回的结果,这时又变成同步操作;要么使用isDone()轮询地判断Future是否完成,这样会耗费CPU的资源。
解决方法:CompletionService和CompletableFuture(按照任务完成的先后顺序获取任务的结果)

2、CompletionService是java1.8之前最好用的方法,

能够实现按照任务完成的先后顺序获取任务的结果。

public class TestCompletionService {private static final String commandstr01 = "hahah";private static final String commandstr02 = "hahah";public static void main(String[] args) throws InterruptedException, ExecutionException {//1、创建一个线程池ExecutorService executorService = Executors.newCachedThreadPool();CompletionService<String> completionService = new ExecutorCompletionService<String>(executorService);completionService.submit(new MyThreadt33(commandstr01));completionService.submit(new MyThreadt44(commandstr01));executorService.shutdown();System.out.println(completionService.take().get());System.out.println(completionService.take().get());}
}class MyThreadt33 implements Callable<String>{private String commandstr;          // 要运行的minglingpublic MyThreadt33(String commandstr) {this.commandstr = commandstr;}@Overridepublic String call() throws Exception {int sum = 0;for (int i = 0; i < 100; i++) {Thread.sleep(200);sum += i;System.out.println("Mythread3: "+i);}return String.valueOf(sum+300000);}
}class MyThreadt44 implements Callable<String>{private String commandstr;          // 要运行的minglingpublic MyThreadt44(String commandstr) {this.commandstr = commandstr;}@Overridepublic String call() throws Exception {int sum = 0;for (int i = 0; i < 50; i++) {Thread.sleep(200);sum += i;System.out.println("Mythread4: "+i);}return String.valueOf(sum+400000);}
}

CompletionService方法可以通过completionService.take().get()方法获取最快完成的线程的返回结果(若当前没有线程执行完成则阻塞直到最快的线程执行结束),第二次调用则返回第二快完成的线程的返回结果。

3、CompletableFuture接口

所谓异步调用其实就是实现一个可无需等待被调函数的返回值而让操作继续运行的方法。简单的讲就是另启一个线程来完成调用中的部分计算,使调用继续运行或返回,而不需要等待计算结果。但调用者仍需要取线程的计算结果。

JDK1.5新增了Future接口,用于描述一个异步计算的结果。虽然 Future 以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。

JDK1.8后提出了CompletableFuture接口实现了Future和CompletionStage两个接口,CompletionStage可以看做是一个异步任务执行过程的抽象(CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段,一个阶段的计算执行可以是一个Function,Consumer或者Runnable。比如:

stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println()))
我们可以基于CompletableFuture创建任务和链式处理多个任务,并实现按照任务完成的先后顺序获取任务的结果。

(1)创建任务

##使用runAsync方法新建一个线程来运行Runnable对象(无返回值);

##使用supplyAysnc方法新建线程来运行Supplier对象(有返回值);

##基于线程池创建

(2)任务的异步处理

不论Future.get()方法还是CompletableFuture.get()方法都是阻塞的,为了获取任务的结果同时不阻塞当前线程的执行,我们可以使用CompletionStage提供的方法结合callback来实现任务的异步处理。

##whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
##whenCompleteAsync:把 whenCompleteAsync 这个任务继续提交给线程池来进行执行,也就是并行执行。

##thenApply:当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化

##thenAccept:thenAccept接收上一阶段的输出作为本阶段的输入,并消费处理,无返回结果。

##thenRun:不关心前一阶段的计算结果,因为它不需要输入参数,进行消费处理,无返回结果。

##thenCombine:会把两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。

##applyToEither :两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的转化操作。

##acceptEither 方法:两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的消耗操作

public class TestCompletableFuture {private static final String commandstr01 = "hahah";private static final String commandstr02 = "hahah";private static final String commandstr03 = "hahah";private static final String commandstr04 = "hahah";public static void main(String[] args) throws InterruptedException, ExecutionException{ExecutorService executorService = Executors.newCachedThreadPool();CompletableFuture.supplyAsync(new MyThreadt444(commandstr02),executorService).whenComplete((result, e) -> {//执行线程执行完以后的操作。System.out.println(result + " " + e);}).exceptionally((e) -> {//抛出异常System.out.println("exception " + e);return "exception";});CompletableFuture.supplyAsync(new MyThreadt333(commandstr02),executorService).whenComplete((result, e) -> {//执行线程执行完以后的操作。System.out.println(result + " " + e);}).exceptionally((e) -> {System.out.println("exception " + e);return "exception";});}
}class MyThreadt333 implements Supplier<String>{private String commandstr;          // 要运行的minglingpublic MyThreadt333(String commandstr) {this.commandstr = commandstr;}@Overridepublic String get() {int sum = 0;for (int i = 0; i < 30; i++) {try {Thread.sleep(200);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}sum += i;System.out.println("Mythread333: "+i);}return String.valueOf(sum+300000);}
}class MyThreadt444 implements Supplier<String>{private String commandstr;          // 要运行的minglingpublic MyThreadt444(String commandstr) {this.commandstr = commandstr;}@Overridepublic String get() {int sum = 0;for (int i = 0; i < 40; i++) {try {Thread.sleep(200);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}sum += i;System.out.println("Mythread444: "+i);}return String.valueOf(sum+400000);}
}

在CompletableFuture接口中除了使用whenComplete还可以使用handle等方法能实现按照任务完成的先后顺序获取任务的结果。

4、几种多线程并发取结果方式的总结

future.get方法阻塞问题的解决,实现按照任务完成的先后顺序获取任务的结果相关推荐

  1. java 多线程 submit future.get方法阻塞问题的解决,实现按照任务完成的先后顺序获取任务的结果

    1.Future Future模式是多线程设计常用的一种设计模式.Future模式可以理解成:我有一个任务,提交给了Future,Future替我完成这个任务.期间我自己可以去做任何想做的事情.一段时 ...

  2. 需要我们了解的SQL Server阻塞原因与解决方法 - sym_cn

    2019独角兽企业重金招聘Python工程师标准>>> 这里通过连接在sysprocesses里字段值的组合来分析阻塞源头,可以把阻塞分为以下5种常见的类型(见表).waittype ...

  3. Java使用Future设置方法超时

    1.使用线程包 java.util.concurrent.Future 2.Future代表一个异步计算的结果. 它提供了方法来检查是否计算已经完成,还是正在计算而处于等待状态,并且也提供了获取计算结 ...

  4. future java 超时_Java使用Future设置方法超时

    1.Future 它提供了方法来检查是否计算已经完成,还是正在计算而处于等待状态,并且也提供了获取计算结果 方法.当计算完成后,只能通过get方法来获取执行结果,必要的话该方法会阻塞.通过cancel ...

  5. .net framework4.6项目的dll升级后,未找到方法“System.String.GetPathsOfAllDirectoriesAbove”解决

    .net framework4.6项目的dll升级后,未找到方法"System.String.GetPathsOfAllDirectoriesAbove"解决 参考文章: (1). ...

  6. 那个软件弹出广告_如何关闭烦人的电脑弹窗广告?5种方法教你轻松解决

    如果要问大家在使用电脑的过程中让人最反感的是什么,我想许多人的回答都会是弹窗广告.一些软件为了给自己创收,完全不顾用户的使用体验,在软件中强行加入广告弹窗模块.这些弹窗广告不仅让人在视觉上烦不胜烦,而 ...

  7. Python Subprocess Popen 管道阻塞问题分析解决

    Python Subprocess Popen 管道阻塞问题分析解决 参考文章: (1)Python Subprocess Popen 管道阻塞问题分析解决 (2)https://www.cnblog ...

  8. springBoot JPA 数据库字段(实体类)带下划线在扩展findBy方法时出错的解决办法

    springBoot JPA 数据库字段(实体类)带下划线在扩展findBy方法时出错的解决办法 参考文章: (1)springBoot JPA 数据库字段(实体类)带下划线在扩展findBy方法时出 ...

  9. Mac Mounty正常卸载方法(mount failed异常解决)

    Mac Mounty正常卸载方法(mount failed异常解决) tags: Mac ● 挂载失败 由于磁盘未正常卸载, 部分扇区被污染导致无法正常加载, 需进行磁盘修复: Windows系统下使 ...

最新文章

  1. SAS 对数据的拼接与串接
  2. python 升级setuptools_linux 安装/升级 python3+setuptools+pip
  3. python项目如何打开_python如何打开_linux如何打开python_python程序打开 - 云+社区 - 腾讯云...
  4. Rightmost Digit
  5. table 内 下拉列表 被遮挡_一个简洁、有趣的无限下拉方案
  6. C语言 const 修饰变量 - C语言零基础入门教程
  7. https p12证书请求解决问题过程
  8. keil和proteus的联调设置
  9. js java传参乱码_【技术贴】解决前台js传参中文乱码
  10. [转]如何编程实现 2 + 2 = 5?
  11. html静态网页制作代码
  12. 视频教程-细说HTML(HTML+HTML5)-HTML5/CSS
  13. 实验11 静态路由配置
  14. TP5 控制器命名大小写问题
  15. 法雷序列的c语言程序,程序设计实践(一).PDF
  16. Java程序员高效学习的六个中肯建议
  17. 企业级地理数据库(sde库)创建 要素服务
  18. 根据国防科大论文确定的特征点坐标拟合平面方程-拟合优度分析
  19. 关于VLAN(虚拟局域网)
  20. ppt怎么做流程图饼图_环形流程图如何绘制?5分钟让你精通绘制技巧

热门文章

  1. 聚焦爬虫案例4:斗图啦
  2. 【pytest】pytest报告插件开源作品
  3. 【FXCG】人民币国际支付份额上升
  4. 短网址、综合短网址、PT短网址生成源代码,含前后端源代码,做一个自己的短链生成网站
  5. 如何使用Excel自定义函数并且全局使用
  6. Windows 关闭8080端口(8080端口被占用)
  7. 使用PotPlayer出现屏幕倒转
  8. libgrape-lite: 提供 GraphScope 的图分析能力
  9. EDUP EP-N8508(RTL8188CUS) Linux驱动安装
  10. Spring A.S 1.0版本迭代日志