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 一样,可以作为函数调用的契约.当你向它请求获得结果,如果 ...
随机推荐
- 于是他错误的点名开始了(trie树)
题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次,然后正好被路过的校长发现了然后就是一顿欧拉欧拉欧拉(详情请见已结束比赛CON900). ...
- 在C++中如何实现文件的读写
一.ASCII 输出为了使用下面的方法, 你必须包含头文件<fstream.h>(译者注:在标准C++中,已经使用<fstream>取代< fstream.h>,所 ...
- 【前行&赛时总结】◇第4站&赛时9◇ CF Round 513 Div1+Div2
◇第4站&赛时9◇ CF Round 513 Div1+Div2 第一次在CF里涨Rating QWQ 深感不易……作blog以记之 ( ̄▽ ̄)" +Codeforces 的门为你打 ...
- 关系型数据库设计——E-R图
一.数据管理技术的三个发展阶段: 1)人工管理阶段(20世纪50年代中期) 特点:数据不保存:应用程序管理数据:数据不共享:数据没有独立性: 2)文件系统阶段(20世纪50年代后—60年代)特点:数据 ...
- JZOJ 5941. 乘
Sample Input Sample Input1: 4 3 9 6 5 8 7 7 Sample Output Sample Output1: 0做法(转自JZOJ):考虑 a 是定值, 而 b ...
- Python学习笔记:第一天python基础
目录 1. python简介 2. python的安装 3. 编写第一个helloword 4. 变量和常量 5. 数据类型 6. 输入 7. if语句 1. python简介 python是在198 ...
- Str_turn
public class Str_turn { public static void main(String args[]) { String Str1 = new String("This ...
- Java+Selenium3自动化测试框架设计系列--href="javascript:void(0)"如何获得元素定位
经过前面两篇文章的铺 垫,我们这篇介绍,webdriver如何处理,一个浏览器上多个窗口之间切换的问题.我们先脑补这样一个测试场景,你在页面A点击一个连接,会在新的 tab窗口打开页面B,这个时候,你 ...
- R语言学习笔记(十五):获取文件和目录信息
file.info() 参数是表示文件名称的字符串向量,函数会给出每个文件的大小.创建时间.是否为目录等信息. > file.info("z.txt") size isdir ...
- python的初体验
最近由于毕业答辩,导致一些博客没有更新,见谅,今天我们开始一些新的内容 1.python的注释 单行注释:# 多行注释: ''' 这是多行注释 我们可以在里面写很多很多的行 ''' 2.编码风格 #c ...