Future&Promise
- Netty 中的Future与JDK中的Future 同名,但是这是两个接口,Netty中的Future继承自JDK中的Future 接口,而Promise又继承自Netty中的Future 接口。
- JDK的Future 功能较弱,只能**同步等待**任务结束(或成功,或失败)才能得到结果
- netty Future 可以实现同步等待任务结束,也可以异步得到结果,但是还是要等待任务结束
- netty promis 不仅有nettyFuture 的功能,而且脱离了任务独立存在,不是被动的只能等待结果,可以作为两个线程间传递结果的容器
功能名称 | JdkFuture | NettyFuture | Promise |
---|---|---|---|
cancel | 取消任务 | ||
isCanceled | 任务是否取消 | ||
isDone | 任务是否完成,不能区分成功与失败 | ||
get | 获取任务结果,阻塞等待 | ||
getNow | 获取任务结果,非阻塞,还未产生结果时返回Null | ||
await | 等待任务结束,如果任务失败,不会抛出异常,而是需要通过isSuccess 判断 | ||
sync | 等待任务结束,如果任务失败,抛出异常 | ||
isSuccess | 判断任务是否成功 | ||
cause | 获取失败信息,非阻塞,如果没有失败,返回null | ||
addLinstener | 添加回调,异步接收结果 | ||
setSuccess | 设置结果成功 | ||
setFailure | 设置结果失败 |
JdkFuture
Future 就是在线程间传递结果或者传递数据的一个容器,而这里jdk的Future 是被动的,必须由执行任务的线程填到Future 里面,而不能是主动的向Future 中去填
package d2;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.concurrent.*;
/**
* @BelongsProject: netty_learn
* @BelongsPackage: d2
* @Author: Wang Haipeng
* @CreateTime: 2021-12-28 14:30
* @Description: jdkfuture 测试
*/
@Slf4j
public class TestJdkFuture {
@Test
public void test1() throws ExecutionException, InterruptedException {
/*1、线程池
JDKFuture 往往是关联线程池使用的*/
ExecutorService service = Executors.newFixedThreadPool(2);
/*2、提交任务
两个参数一个是Callable 一个是Runnable 都是任务,但是Callable 是有返回值的
详细逻辑和计算的是线程池中的线程,但是要获取结果的则是主线程
通过future 来让主线程和线程池中的线程进行通信,通过future获取子线程执行后的结果
*/
Future<Integer> future = service.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.debug("执行计算");
Thread.sleep(1000);
return 50;
}
});
/**
* 2、主线程通过future 获取结果
* 这里主线程会阻塞,并同步等待子线程的计算,通过get则获取任务结果
* 当线程池中的线程计算机结束了,就唤醒主线程,打印输出
*/
log.debug("等待结果");
Integer integer = future.get();
log.debug("子线程的计算结果为:{}",integer);
}
}
NettyFuture
@Slf4j
public class TestNettyFuture {
@Test
public void test(){
/*1、EventLoop
也是需要基于线程池的,但是Netty中的线程池叫EventLoop,但是这个线程池中只有一个线程
NioEventLoopGroup 中有多个EventLoop,但是每个EventLoop注意只有一个线程
*/
NioEventLoopGroup eventLoopGroup =new NioEventLoopGroup();
EventLoop eventLoop = eventLoopGroup.next();
/*2、提交任务*/
Future<Integer> future = eventLoop.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.debug("执行计算");
return 50;
}
});
future.addListener(new GenericFutureListener<Future<? super Integer>>() {
@Override
public void operationComplete(Future<? super Integer> future) throws Exception {
/*调用回调方法的前提肯定是任务已经执行结果了,所以不需要去阻塞了,这也是回调方法和异步的联系
* 所以这里是get() 还是getNow() 并没有区别
*
* TODO:为什么在这里执行没问题但是不打印日志?
* */
log.debug("{}",future.getNow());
}
});
}
}
通过addListener 的方式执行future.getNow() 是由执行线程进行的而不是主线程
NettyPromis
JdkFuture和NettyFuture 中的future 对象并不是主动创建的,而是线程执行时返回的结果
子线程装入结果:
promise 是主动创建的,这和被动创建的future 本身就有本质区别
package d2;
import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.DefaultPromise;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.concurrent.ExecutionException;
/**
* @BelongsProject: netty_learn
* @BelongsPackage: d2
* @Author: Wang Haipeng
* @CreateTime: 2021-12-28 15:48
* @Description: promise 测试类
*/
@Slf4j
public class TestNettyPromise {
@Test
public void test() throws ExecutionException, InterruptedException {
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
EventLoop eventLoop = eventLoopGroup.next();
/*1、可以主动创建Promise,作为结果的容器,而不是必须创建*/
DefaultPromise<Integer> promise = new DefaultPromise<>(eventLoop);
new Thread(()->{
log.debug("开始计算");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*2、任意线程执行task,计算完毕装入计算结果*/
promise.setSuccess(50);
},"计算线程").start();
/*3、接收结果*/
log.debug("等待结果");
System.out.println(promise.get());
}
}
不仅可以填充计算的结果,还可以填充异常
子线程装入异常:
package d2;
import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.DefaultPromise;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.concurrent.ExecutionException;
/**
* @BelongsProject: netty_learn
* @BelongsPackage: d2
* @Author: Wang Haipeng
* @CreateTime: 2021-12-28 15:48
* @Description: promise 测试类
*/
@Slf4j
public class TestNettyPromise {
@Test
public void test() throws ExecutionException, InterruptedException {
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
EventLoop eventLoop = eventLoopGroup.next();
/*1、可以主动创建Promise,作为结果的容器*/
DefaultPromise<Integer> promise = new DefaultPromise<>(eventLoop);
new Thread(()->{
log.debug("开始计算");
try {
Thread.sleep(1000);
throw new RuntimeException("计算错误!");
} catch (RuntimeException e) {
/*传递异常*/
promise.setFailure(e);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"计算线程").start();
/*3、接收结果*/
log.debug("等待结果");
try {
log.debug(String.valueOf(promise.get()));
} catch (Exception e){
log.error(e.getMessage());
}
}
}
todo:还是没有感觉到promise 和future 的更大的区别?比如说是否promise 能由主线程传递给子线程值,这里测试之后发现
promise.setSuccess 是希望promise 等于null,也就是不被赋值的,这里不打算深究,留到整体研究源码时再进行研究,这里只做记录。