在异步处理时,我们常常需要用到这些接口:jdk中的Future和CompleableFuture,netty中的Future和promise。
其中jdk的Future和CompleableFuture在上篇文章中已经讲过了,现在先来讲讲netty的Future和promise。
Future
首先要说明 netty 中的 Future 与 jdk 中的 Future 同名,但是是两个接口,netty 的 Future 继承自 jdk 的 Future
- jdk Future 只能同步等待任务结束(或成功、或失败)才能得到结果
- netty Future 可以同步等待任务结束得到结果,也可以异步方式得到结果,但都是要等任务结束
Future需要通过线程来获取结果,在netty中,我们常常通过EventLoopGroup获取Future对象。
随便提一下,excute方法只能提交Runnable任务,没有返回结果。所以我们使用submit方法执行Callable任务才能获取返回结果future。
异步处理:即获取返回结果这个操作是由其他线程(这里是enentLoop)执行的,即在future的操作完成后,enentLoop会执行operationComplete方法。在整个过程中,主线程不会被堵塞,会一直往下执行。
下面通过addListener方法异步获取返回结果:
public class TestNettyFuture {
public static void main(String[] args) throws ExecutionException, InterruptedException {
NioEventLoopGroup group = new NioEventLoopGroup();
EventLoop eventLoop = group.next();
Future<Integer> future = eventLoop.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.debug("执行计算");
Thread.sleep(1000);
return 70;
}
});
// log.debug("等待结果");
// log.debug("结果是 {}", future.get());
future.addListener(new GenericFutureListener<Future<? super Integer>>(){
@Override
public void operationComplete(Future<? super Integer> future) throws Exception {
log.debug("接收结果:{}", future.getNow());
}
});
}
}
Promise
Future对象是线程返回得到的结果,依赖线程才能创建。而Promise对象可以主动创建,不需要依赖线程。
netty Promise 不仅有 netty Future 的功能,而且脱离了任务独立存在,只作为两个线程间传递结果的容器,并且可以设置状态(成功还是失败)。
创建promise对象,下面的enentLoop相当于一个线程,用于处理结果的通知和回调。
DefaultPromise<Integer> promise = new DefaultPromise<>(eventLoop);
随便提一下:promise的await方法是非阻塞的,意思是执行await时,当前的代码不会往下走,不会占用CPU,而是会让出CPU资源,用于执行其他任务。当promise被唤醒(设置结果)后,会用EventLoop来通知这个线程来恢复执行没走完的代码。所以我们可以在get()之前使用await,这样就可以解放CPU。
例子:
public class TestNettyPromise {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1. 准备 EventLoop 对象
EventLoop eventLoop = new NioEventLoopGroup().next();
// 2. 可以主动创建 promise, 结果容器
DefaultPromise<Integer> promise = new DefaultPromise<>(eventLoop);
new Thread(() -> {
// 3. 任意一个线程执行计算,计算完毕后向 promise 填充结果
log.debug("开始计算...");
try {
int i = 1 / 0;
Thread.sleep(1000);
promise.setSuccess(80);
} catch (Exception e) {
e.printStackTrace();
promise.setFailure(e);
}
}).start();
// 4. 接收结果的线程
log.debug("等待结果...");
log.debug("结果是: {}", promise.get());
}
}
Future & Promise & compleableFuture
- jdk的future同步等待,并且不能判断结果成功还是失败。
- netty的future可以非阻塞等待,用getNow如果结果还没有的话返回null
- promise储存东西+结果(成功或者失败)使用的是setSuccess方法和setFailure方法,用get方法获取返回结果。同时可以在get之前await来让出CPU。
- 而java的compleableFuture可以异步获取结果,并且储存东西使用的是complete方法,用get方法阻塞获取结果。
功能/名称 | jdk Future | netty Future | Promise(这里的任务指的是setSuccess()或者setFailure(),二者都算任务结束) |
cancel | 取消任务 | 同上 | 同上 |
isCanceled | 任务是否取消 | 同上 | 同上 |
isDone | 任务是否完成,不能区分成功失败 | 同上 | 同上 |
get | 获取任务结果,阻塞等待 | 同上 | 同上 |
getNow | - | 获取任务结果,非阻塞,还未产生结果时返回 null | 同上 |
await | - | 等待任务结束,如果任务失败,不会抛异常,而是通过 isSuccess 判断 | 同上 |
sync | - | 等待任务结束,如果任务失败,抛出异常 | 同上 |
isSuccess | - | 判断任务是否成功 | 同上 |
cause | - | 获取失败信息,非阻塞,如果没有失败,返回null | 同上 |
addLinstener | - | 添加回调,异步接收结果 | 同上 |
setSuccess | - | - | 设置成功结果 |
setFailure | - | - | 设置失败结果 |