Netty源码中大量使用异步回调机制,不管是connect还是write,甚至bind操作都是异步回调。Netty的I/O操作都是异步的,这归功于Netty两大接口Future和Promise
Future
-
JDK Future
我们知道在JDK中就引入了Future机制,JDK Futrue通过
get()
方法回调task返回结果,如果task尚未结束,则同步等待返回结果。同时JDK Future还有一些状态标识方法,比如isDone()
,isCancelled()
JDK Future非常好理解,FutureTask实现了Future,用一个小测试用例描述一下
@Test public void testFuture() throws Exception { FutureTask<String> task = new FutureTask<>(() -> { // 模拟task过程 // 委托代理人完成task,代理人耗时6s,帮助金主盈利一个小目标 Thread.sleep(6000L); return "账户到账一个亿"; }); // 金主将任务委派给代理人 new Thread(task).start(); Thread.sleep(1000L); System.out.println("金主玩了1s的麻将"); // 金主突然想起代理人是否完成了小目标 if (!task.isDone()) { Thread.sleep(2000L); System.out.println("代理人没有完成task,金主继续玩了2s麻将"); } // 金主又想看看代理人是否完成了小目标 // 由于代理人还没有完成目标,金主还需要阻塞等待3s System.out.println("金主麻将输了一个亿,打算等代理人3s吧"); System.out.println("......"); System.out.println("3s倒计时"); String money = task.get(); System.out.println(money); } 输出:Tests passed: 1 of 1 test - 6sec 44ms 金主玩了1s的麻将 代理人没有完成task,金主继续玩了2s麻将 金主麻将输了一个亿,打算等代理人3s吧 ...... 3s倒计时 账户到账一个亿
-
Netty Future
Netty中的Future和JDK中的Future同名,但它们是两个接口。Netty Future在继承JDK Future的基础上,扩展了自己的方法:
public interface Future<V> extends java.util.concurrent.Future<V> { // 任务执行成功,返回true boolean isSuccess(); // 任务被取消,返回true boolean isCancellable(); // 支付执行失败,返回异常 Throwable cause(); // 添加Listener,异步非阻塞处理回调结果 Future<V> addListener(GenericFutureListener<? extends Future<? super V>> listener); Future<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners); // 移除Listener Future<V> removeListener(GenericFutureListener<? extends Future<? super V>> listener); Future<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners); // 同步阻塞等待任务结束;执行失败话,会将“异常信息”重新抛出来 Future<V> sync() throws InterruptedException; Future<V> syncUninterruptibly(); // 同步阻塞等待任务结束,和sync方法一样,只不过不会抛出异常信息 Future<V> await() throws InterruptedException; Future<V> awaitUninterruptibly(); boolean await(long timeout, TimeUnit unit) throws InterruptedException; boolean await(long timeoutMillis) throws InterruptedException; boolean awaitUninterruptibly(long timeout, TimeUnit unit); boolean awaitUninterruptibly(long timeoutMillis); // 非阻塞,获取执行结果 V getNow(); // 取消任务 @Override boolean cancel(boolean mayInterruptIfRunning); }
我们知道JDK的Future任务结果获取需要主动查询(即主动回调),Future(无特殊说明指的是Netty Future,后文都以Futrue代替Netty Future)通过监听器Listener做到异步非阻塞处理任务结果(即被动回调)。
Future是怎样做到被动回调的呢?
类比JDK的FutureTask类,我们需要看看PromiseTask类。PromiseTask实现了Future接口,本身也实现了Runnable接口,所以和FutureTask原理一样。在PromiseTask#run()方法里执行异步任务,并返回callable.call()结果,并且在接收到结果后,会继续逐个通知各个监听者。PromiseTask#run()方法作为另外一个线程的业务代码,会在另外的线程上运行,最终也会由另外的线程回调监听者,完成回调逻辑。主线程完全不用管回调的监听业务,所以称为被动回调。
public void run() { try { if (this.setUncancellableInternal()) { // 获取任务结果方法 V result = this.runTask(); // 会调用通知监听方法 this.setSuccessInternal(result); } } catch (Throwable var2) { this.setFailureInternal(var2); } } final V runTask() throws Exception { Object task = this.task; if (task instanceof Callable) { // 返回任务结果 return ((Callable)task).call(); } else { ((Runnable)task).run(); return null; } } protected final Promise<V> setSuccessInternal(V result) { // setSuccess(result)方法通过层层调用,最终会调用setValue0(result) super.setSuccess(result); this.clearTaskAfterCompletion(true, COMPLETED); return this; } private boolean setValue0(Object objResult) { if (RESULT_UPDATER.compareAndSet(this, null, objResult) || RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) { if (checkNotifyWaiters()) { // 通知监听者 notifyListeners(); } return true; } return false; }
Future同步阻塞方式有两种,
sync()
和await()
,区别在于sync()
方法在任务失败后,会把异常信息抛出;await()
方法对异常信息不做任何处理。阅读源码可知sync()
其实调的就是await()
。推荐使用sync()
方法public Promise<V> sync() throws InterruptedException { this.await(); this.rethrowIfFailed(); return this; }
Promise
Promise接口继承了Future接口,在此基础上,Promise还提供了设置返回值和异常,并立即通知listeners的功能。一旦 setSuccess(…) 或 setFailure(…) 后,那些 await() 或 sync() 的线程就会从等待中返回。
接口定义:
public interface Promise<V> extends Future<V> {
// 执行成功,设置返回值,并通知所有listener,如果已经设置,则会抛出异常
Promise<V> setSuccess(V result);
// 设置返回值,如果已经设置,返回false
boolean trySuccess(V result);
// 执行失败,设置异常,并通知所有listener
Promise<V> setFailure(Throwable cause);
boolean tryFailure(Throwable cause);
// 标记Future不可取消
boolean setUncancellable();
@Override
Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
@Override
Promise<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
@Override
Promise<V> removeListener(GenericFutureListener<? extends Future<? super V>> listener);
@Override
Promise<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
@Override
Promise<V> await() throws InterruptedException;
@Override
Promise<V> awaitUninterruptibly();
@Override
Promise<V> sync() throws InterruptedException;
@Override
Promise<V> syncUninterruptibly();
}
实现定义:public class DefaultPromise extends AbstractFuture implements Promise
public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
......
@Override
public Promise<V> setSuccess(V result) {
if (setSuccess0(result)) {
return this;
}
throw new IllegalStateException("complete already: " + this);
}
private boolean setSuccess0(V result) {
return setValue0(result == null ? SUCCESS : result);
}
private boolean setValue0(Object objResult) {
if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
if (checkNotifyWaiters()) {
// 通知listeners
notifyListeners();
}
return true;
}
return false;
}
}
ChannelFuture和ChannelPromise
-
ChannelFunture
跟Channel的操作有关,Netty是异步的,许多方法返回的都是ChannelFuture,可添加监听者获取Channel异步操作的结果;当然也可等待获取,但最好不要在handler中同步等待
ChannelFuture就两种状态Uncompleted(未完成)和Completed(完成),Completed包括三种,执行成功,执行失败和任务取消。注意:执行失败和任务取消都属于Completed。
/** * ChannelFuture的状态转换 +---------------------------+ | Completed successfully | +---------------------------+ +----> isDone() = true | +--------------------------+ | | isSuccess() = true | | Uncompleted | | +===========================+ +--------------------------+ | | Completed with failure | | isDone() = false | | +---------------------------+ | isSuccess() = false |----+----> isDone() = true | | isCancelled() = false | | | cause() = non-null | | cause() = null | | +===========================+ +--------------------------+ | | Completed by cancellation | | +---------------------------+ +----> isDone() = true | | isCancelled() = true | +---------------------------+ */ public interface ChannelFuture extends Future<Void> { // 获取channel通道 Channel channel(); @Override ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> listener); @Override ChannelFuture addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners); @Override ChannelFuture removeListener(GenericFutureListener<? extends Future<? super Void>> listener); @Override ChannelFuture removeListeners(GenericFutureListener<? extends Future<? super Void>>... listeners); @Override ChannelFuture sync() throws InterruptedException; @Override ChannelFuture syncUninterruptibly(); @Override ChannelFuture await() throws InterruptedException; @Override ChannelFuture awaitUninterruptibly(); // 标记Futrue是否为Void,如果ChannelFuture是一个void的Future,不允许调用addListener(),await(),sync()相关方法 boolean isVoid(); }
-
ChannelPromise
ChannelPromise接口只是综合了ChannelFuture和Promise接口,没有新增功能。
截至到目前,异步监听相关的接口已经介绍完了,让我们通过一张图来概括下:
应用实战
public class ChannelFutureTest {
@Test
public void testDefaultPromise() throws InterruptedException, ExecutionException {
EventExecutor executor = new SelfEventExecutor();
final Promise<String> promise = new DefaultPromise<String>(executor);
// 金主派会计审查代理人是否转错帐户
promise.addListener(new GenericFutureListener<Future<? super String>>() {
@Override
public void operationComplete(Future<? super String> future) throws Exception {
System.out.println("会计审查-结果:" + future.get());
}
});
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
// 模拟task过程
// 委托代理人完成task,代理人耗时6s,帮助金主盈利一个小目标
Thread.sleep(6000L);
// 代理人将利润私有化
promise.setSuccess("代理人账户到账一个亿");
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
// 金主将任务委派给代理人
thread.start();
System.out.println("金主下发任务");
System.out.println("金主玩了2s的麻将");
Thread.sleep(2000l);
// 金主突然想起代理人是否完成了小目标
if (!promise.isDone()) {
System.out.println("代理人没有完成task,金主继续玩了6s麻将");
Thread.sleep(6000l);
}
// 金主又想看看代理人是否完成了小目标
System.out.println("金主麻将输了一个亿,金主主动查看账户:" + promise.get());
// 主线程不能结束
Thread.sleep(Integer.MAX_VALUE);
}
class SelfEventExecutor extends SingleThreadEventExecutor {
public SelfEventExecutor() {
this(null);
}
public SelfEventExecutor(EventExecutorGroup parent) {
this(parent, new DefaultThreadFactory(SelfEventExecutor.class));
}
public SelfEventExecutor(EventExecutorGroup parent, ThreadFactory threadFactory) {
super(parent, threadFactory, true);
}
@Override
protected void run() {
Runnable task = takeTask();
if (task != null) {
task.run();
}
}
}
}
输出:
金主下发任务
金主玩了2s的麻将
代理人没有完成task,金主继续玩了6s麻将
会计审查-结果:代理人账户到账一个亿
金主麻将输了一个亿,金主主动查看账户:代理人账户到账一个亿