Runnable、Callable、Future和CompletableFuture
一、Runnable
Runnable非常简单,只需要实现一个run方法即可,没有参数,也没有返回值。可以以new Thread的方式去运行,当然更好的方式在放到excutorPool中去运行。
二、Callabe和Future
Callable也用来实现异步调用,但是可以返回参数,并可以抛出异常。
Future可以认为是对java异步执行机制的另一种包装。
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
通过Future,可以知道异步线程是否完成了任务,并可以拿到相应的值。
FutureTask是Future的实现类,在具体的使用中可以和Callable一起使用。
public Class FutureTask<V> implements Runnable, Future<V>, RunnableFuture<V>{
public FutureTask(Callable<V> callable);
public FutureTask(Runnable runnable, V result);
public boolean cancel(boolean mayInterruptIfRunning);
public V get();
public V get(long timeout,TimeUnit unit);
public boolean isCancelled();
public boolean isDone();
public void run();
}
举例如下。
……
Callable<String> callable = new Callable<String>(){
@override
public String call() throws Exception{
Thread.sleep(5000);
return "Done";
}
}
FutureTask<String> task = new FutureTask<String>(callable);
new Thread(task).start();
.......
if(task.isDone() == false){//异步操作未结束
//do something here,
}
String str = task.get();
........
首先构建了一个callable方法,紧接着构建了FutureTask并启动了它。
第16行开始等待这个异步任务结束,其实也可以没有16行,直接进行20行,但20行也是个阻塞方法,会一直等待任务结束。
三、ListenableFuture和CompletableFuture
在上面Future的实现中,可以看到需要主线程一直判断任务是否完成,google对Future进行了扩展,就是ListenableFuture,增加了void addListener(Runnable listener, Executor executor)方法,这样,一旦异步任务执行完毕,就可以迅速拿到结果,更加自然。
代码片段一: 获取ListenableFuture
ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
final ListenableFuture<Integer> listenableFuture = executorService.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("call execute..");
TimeUnit.SECONDS.sleep(1);
return 7;
}
});
代码片段二:通过ListenableFuture的addListener方法来实现回调
listenableFuture.addListener(new Runnable() {
@Override
public void run() {
try {
System.out.println("get listenable future's result " + listenableFuture.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}, executorService);
代码片段三:通过Futures的静态方法addCallback给ListenableFuture添加回调函数
Futures.addCallback(listenableFuture, new FutureCallback<Integer>() {
@Override
public void onSuccess(Integer result) {
System.out.println("get listenable future's result with callback " + result);
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
})
推荐使用第二种方法,因为第二种方法可以直接得到Future的返回值,或者处理错误情况。本质上第二种方法是通过调动第一种方法实现的,做了进一步的封装。
那么,是否就可以用ListenableFuture完全取代Future了?其实也要看情况
1、如果一个主任务开始执行,然后需要执行各个小任务,并且需要等待返回结果,统一返回给前端,此时Future和ListenableFuture作用几乎差不多,都是通过get()方法阻塞等待每个任务执行完毕返回。
2、 如果一个主任务开始执行,然后执行各个小任务,主任务不需要等待每个小任务执行完,不需要每个小任务的结果,此时用ListenableFuture非常合适,它提供的FutureCallBack接口可以对每个任务的成功或失败单独做出响应。
CompletableFuture是JDK8中才出现的概念,算是对google的ListenableFuture的回应吧,而且更强大。
CompletableFuture能够将回调放到与任务不同的线程中执行,也能将回调作为继续执行的同步函数,在与任务相同的线程中执行。它避免了传统回调最大的问题,那就是能够将控制流分离到不同的事件处理器中。
CompletableFuture弥补了Future模式的缺点。在异步的任务完成后,需要用其结果继续操作时,无需等待。可以直接通过thenAccept、thenApply、thenCompose等方式将前面异步处理的结果交给另外一个异步事件处理线程来处理。
获得一个CompletableFuture
| runAsync(Runnable runnable) | 使用ForkJoinPool.commonPool()作为它的线程池执行异步代码。 |
| runAsync(Runnable runnable, Executor executor) | 使用指定的thread pool执行异步代码。 |
| supplyAsync(Supplier<U> supplier) | 使用ForkJoinPool.commonPool()作为它的线程池执行异步代码,异步操作有返回值 |
| supplyAsync(Supplier<U> supplier, Executor executor) | 使用指定的thread pool执行异步代码,异步操作有返回值 |
可以使用上面的静态类来获取一个CompletableFuture,前两个和后两个的区别,也类同与Runnable和Callable的区别。
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("Hello");
});
try {
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("CompletableFuture");
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("CompletableFuture");
如果只是看上面的代码,好像和Future没什么区别,其实CompletableFuture提供的更多更强大的功能。
计算结果完成时的处理
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
转换
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
还有其他更多的语义,无法一一赘述。
参考了如下文档
https://www.jianshu.com/p/4897ccdcb278
Runnable、Callable、Future和CompletableFuture的更多相关文章
- Future、 CompletableFuture、ThreadPoolTaskExecutor简单实践
一 Future(jdk5引入) 简介: Future接口是Java多线程Future模式的实现,可以来进行异步计算. 可以使用isDone方法检查计算是否完成,或者使用get阻塞住调用线程,直到计算 ...
- Java并发编程系列一:Future和CompletableFuture解析与使用
一.Future模式 Java 1.5开始,提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果. Future接口可以构建异步应用,是多线程开发中常见的设计模式. 当 ...
- java.util.concuttent Callable Future详解
在传统的多线程实现方式中(继承Thread和实现Runnable)无法直接获取线程执行的返回结果,如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦. 从 ...
- Future接口和FutureTask类【FutureTask实现了Runnable和Future接口】
Future API: public interface Future<V> { /** * Attempts to cancel execution of this task. This ...
- Java 并发编程——Callable+Future+FutureTask
Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...
- 12 Callable & Future & FutureTask
创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就必须通过共享变量或者使用 ...
- java 并发runable,callable,future,futureTask
转载自:http://www.cnblogs.com/dolphin0520/p/3949310.html package future_call; import java.util.concurre ...
- Java Callable Future Example(java 关于Callable,Future的例子)
Home » Java » Java Callable Future Example Java Callable Future Example April 3, 2018 by Pankaj 25 C ...
- Java并发编程:ThreadPoolExecutor + Callable + Future(FutureTask) 探知线程的执行状况
如题 (总结要点) 使用ThreadPoolExecutor来创建线程,使用Callable + Future 来执行并探知线程执行情况: V get (long timeout, TimeUnit ...
- Java8 中增强 Future:CompletableFuture
增强的 Future:CompletableFuture CompletableFuture(它实现了 Future 接口) 和 Future 一样,可以作为函数调用的契约.当你向它请求获得结果,如果 ...
随机推荐
- P1330 封锁阳光大学 DFS+染色
题目链接:https://www.luogu.org/problemnew/show/P1330 这个题有意思,如果能想到染色,就会很简单,但若想不到就很麻烦 要想把一条边封锁,就必须且只能占据这条边 ...
- ABAP术语-BAPI Explorer
BAPI Explorer 原文:http://www.cnblogs.com/qiangsheng/archive/2007/12/24/1012110.html Tool for developi ...
- iframe中的页面在IE全屏模式下没有滚动条,正常模式有滚动条
这个问题在其他浏览器都不会出现,唯独IE不行,搜遍了百度以及各大论坛网站,都找不到这个问题的解决方案,只好自己整了. 造成这个问题的原因很简单,就是刚开始的滚动条我用的是iframe的滚动条,ifra ...
- 配置Github秘钥
Git安装完成后,需要手动配置ssh密钥 配置github的ssh密钥: (1)打开Git Bash查看电脑上是否已经存在SSH密钥: 输入 cd ~/.ssh 若如上图显示无法找到该文件则要创建新的 ...
- HTML中的【块】与【内嵌】
块元素与内嵌元素 块的特征 默认独占一行 没有宽度时默认撑满一行 支持所有的css命令 内嵌的特征 同行可以连续跟同类的标签 内容撑开宽度 不支持宽高 不支持上下的内外边距 代码换行被解析 块与内嵌的 ...
- 获取cookie,设置cookie,删除cookie
//获取cookie export const getCookie = (name) => { var arr, reg = new RegExp("(^| )" + nam ...
- Hadoop(11)-MapReduce概述和简单实操
1.MapReduce的定义 2.MapReduce的优缺点 优点 缺点 3.MapReduce的核心思想 4.MapReduce进程 5.常用数据序列化类型 6.MapReduce的编程规范 用户编 ...
- 2.从print到自省
print是一个函数 为什么print是一个函数呢?可以在交互式解释器下 输入: >>> type(print) 输出: <class 'builtin_function_ ...
- linux文件操作篇 (一)文件属性与权限
文件的属性和权限是linux中 目录 和 文件 的两个基本特性. #属性: . 所有者属性 . 访问权限属性 -rwxrwxr-x #第一个字符是文件类别 -表示 普通文件 d 表示目录 b 表示 ...
- WPF中的ControlTemplate(控件模板)
原文:WPF中的ControlTemplate(控件模板) WPF中的ControlTemplate(控件模板) ...