一.JDK的Future,Netty的Future,Netty的Promise三者之间关系与区别
先看继承图
可以看到Netty在Jdk原生的Future上自己扩展了一个Future接口,而在这个扩展的Future接口的基础上又扩展了Promise接口,所以对于这三者之间的区别如下:
JDK Future:只能同步等待任务结束(无论成功还是失败)才能得到结果。
Netty Future:可以同步等待任务结束得到结果,也可以异步方式得到结果,前提是任务必须要结束。
Netty Promise:不仅有 netty Future 的功能,而且脱离了任务独立存在,只作为两个线程间传递结果的容器。
二.Netty的Future
io.netty.util.concurrent.Future
上面说了Netty中的Future与JDK的Future最大的不同在于,使用JDK的Future的时候获取方只能同步等待任务执行的结果,而使用Netty的Future提供了addListener和addListeners方法去注册监听器,使得任务执行完成之后可以通过监听器异步的通知获取方
三.Netty的promise
在具体说promise之前,我们先说一个结论,那就是在Netty中promise底层的实现原理其实就是两个线程间充分利用JDK自身的wait和notify方法去进行线程间的交互,把promise实例当做是锁的对象,从而形成了promise自身可以看做是一个独立容器的存在
我们先来看下Promise接口io.netty.util.concurrent.Promise
public interface Promise<V> extends Future<V> {
/**
* 给promise设置一个成功的结果值,并且唤醒阻塞的线程以及执行响应的监听器回调
* 如果已经设置了成功或失败,它将抛出一个{@link IllegalStateException}
*/
Promise<V> setSuccess(V result);
/**
* 给promise设置一个成功的结果值,并且唤醒阻塞的线程以及执行响应的监听器回调
* 与setSuccess方法不同的是,这个方法如果设置成功结果值失败的话则不会抛出异常
*
* @return {@code true} if and only if successfully marked this future as
* a success. Otherwise {@code false} because this future is
* already marked as either a success or a failure.
*/
boolean trySuccess(V result);
/**
* 给promise设置一个失败的异常,并且唤醒阻塞的线程以及执行响应的监听器回调
* 如果已经设置了成功或失败,它将抛出一个{@link IllegalStateException}
*/
Promise<V> setFailure(Throwable cause);
/**
* 给promise设置一个失败的异常,并且唤醒阻塞的线程以及执行响应的监听器回调
* 与setFailure方法不同的是,这个方法如果设置失败异常失败的话则不会抛出异常
*
* @return {@code true} if and only if successfully marked this future as
* a failure. Otherwise {@code false} because this future is
* already marked as either a success or a failure.
*/
boolean tryFailure(Throwable cause);
/**
* 设置这个promise无法取消
*
* @return {@code true} 当且仅当成功地将此promise标记为不可取消或它已经完成而未被取消。 {@code false}如果该promise已经被取消
*/
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();
}
可以看到promise接口继承于Netty的Future接口,新增了几个设置结果值的方法,这几个设置结果值的方法是干什么的呢?我们上面说过promise就类似于一个容器,当一个线程在执行的过程中可以往容器中去设置结果值,另一个线程可以监听这个结果值去做出不同的处理。并且这个接口还重写了Future接口中返回值是Future的方法,把原来Future返回值改成Promise返回值
1.DefaultPromise
DefaultPromise是Netty中对promise的默认实现
示例代码如下:
DefaultEventExecutor executor = new DefaultEventExecutor();
final DefaultPromise<String> promise = new DefaultPromise<>(executor);
long start = System.currentTimeMillis();
new Thread(() -> {
try {
Thread.sleep(5000);
promise.setSuccess("success");
System.out.println("执行完成...");
} catch (Exception e) {
e.printStackTrace();
promise.setFailure(e);
}
}).start();
promise.sync();
System.out.println("耗时:" + (System.currentTimeMillis() - start));
上面这段代码的效果就是开启了一个线程,然后主线程通过promise的sync方法进行同步,线程执行的时候先休眠5s,休眠完了之后就设置一个成功的结果值,当设置完之后sync方法就会解除阻塞,我们看下执行结果:
那么Netty是怎么实现这种promise模式的呢?下面就通过分析DefaultPromise去看下它是怎么实现
(1)设置结果值
/**
* 结果值
*/
private volatile Object result;
/**
* 当调用setSuccess方法的时候,如果参数传入的是null,那么会把null替换成这个SUCCESS对象
*/
private static final Object SUCCESS = new Object();
/**
* 当调用setUncancellable方法的时候,如果此时结果值等于null,会把null替换成这个UNCANCELLABLE对象
*/
private static final Object UNCANCELLABLE = new Object();
DefaultPromise中有一个result属性值用来存储设置的结果值,我们可以通过setSuccess,trySuccess,setFailure,tryFailture,setUncancellable方法去对这个属性设置结果值,代码如下:
public Promise<V> setSuccess(V result) {
if (setSuccess0(result)) {
return this;
}
throw new IllegalStateException("complete already: " + this);
}
public boolean trySuccess(V result) {
return setSuccess0(result);
}
public Promise<V> setFailure(Throwable cause) {
if (setFailure0(cause)) {
return this;
}
throw new IllegalStateException("complete already: " + this, cause);
}
public boolean tryFailure(Throwable cause) {
return setFailure0(cause);
}
public boolean setUncancellable() {
if (RESULT_UPDATER.compareAndSet(this, null, UNCANCELLABLE)) {
return true;
}
Object result = this.result;
return !isDone0(result) || !isCancelled0(result);
}
这些方法最终都会调用setValue0方法去设置具体的结果值
/**
* 设置结果值(给result属性赋值)
* @param objResult 要设置的结果值
* @return true=>设置成功,false=>设置失败
*/
private boolean setValue0(Object objResult) {
// 条件成立:当前result的值是null或者是UNCANCELLABLE
if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
// 判断是否存在加了当前promise锁的线程,如果存在会把所有线程唤醒
if (checkNotifyWaiters()) {
// 回调监听器
notifyListeners();
}
return true;
}
// 返回false说明result的值不等于null或者UNCANCELLABLE
return false;
}
可以看到当每次设置结果值的时候都会有机会去回调监听器(监听器通过addListener方法添加),并且还会调用checkNotifyWaiters方法去解除阻塞的线程
(2)同步阻塞
public Promise<V> sync() throws InterruptedException {
await();
rethrowIfFailed();
return this;
}
private void rethrowIfFailed() {
Throwable cause = cause();
if (cause == null) {
return;
}
PlatformDependent.throwException(cause);
}
可以看到sync方法其实就是调用await方法,只不过使用sync方法同步的时候如果设置了异常结果值的话会往上抛出异常
public Promise<V> await() throws InterruptedException {
if (isDone()) {
return this;
}
if (Thread.interrupted()) {
throw new InterruptedException(toString());
}
checkDeadLock();
// 加锁,注意这里的锁对象是当前promise实例,每一个线程在占有promise锁之后通过wait方法进行阻塞,并且释放promise锁,
// 后面通过这个promise实例调用notifyAll方法就可以唤醒所有加了这个promise锁的线程了
synchronized (this) {
// 循环条件:isDone() == false
while (!isDone()) {
// 等待线程数量+1
incWaiters();
try {
// 调用wait方法阻塞线程
// 当线程唤醒之后会再次进入循环,此时循环条件就会不成立,此时就会跳出循环
wait();
} finally {
// 线程唤醒后把线程数量-1
decWaiters();
}
}
}
return this;
}
await方法中阻塞所使用的方法是jdk原生的wait方法,判断是否阻塞的条件就是isDone方法
public boolean isDone() {
return isDone0(result);
}
private static boolean isDone0(Object result) {
return result != null && result != UNCANCELLABLE;
}
isDone方法判断的逻辑就是结果值不为空并且不为UNCANCELLABLE,也就是说如果我们手动调用了上面设置结果值的那几个方法(除了setUncancellable),那么isDone方法就会返回true
(3)阻塞唤醒
/**
* 检查是否有加了当前promise锁的线程,如果有,唤醒所有线程
* @return {@code true} if there are any listeners attached to the promise, {@code false} otherwise.
*/
private synchronized boolean checkNotifyWaiters() {
// 条件成立:存在加了当前promise锁的线程
if (waiters > 0) {
// 唤醒所有在当前promise实例上加锁阻塞的线程
notifyAll();
}
return listeners != null;
}
在设置结果值的方法中我们已经知道每次设置结果值都会调用checkNotifyWaiters方法去唤醒被阻塞的线程,其实里面很简单就是调用jdk原生的notifyAll方法去唤醒在wait方法上阻塞的线程,而当阻塞的线程从wait方法被唤醒之后会再次通过isDone方法去判断是否已经设置了结果值,由于已经设置了结果值所以会跳出while循环结束await方法
(4)执行监听器回调
private void notifyListeners() {
EventExecutor executor = executor();
// 条件成立:当前线程是指定的EventLoop线程
if (executor.inEventLoop()) {
final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
final int stackDepth = threadLocals.futureListenerStackDepth();
if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
threadLocals.setFutureListenerStackDepth(stackDepth + 1);
try {
// 回调监听器
notifyListenersNow();
} finally {
threadLocals.setFutureListenerStackDepth(stackDepth);
}
return;
}
}
// 代码执行到这里说明当前的执行线程不是指定的EventLoop线程
// 那么此时就需要把监听器回调放到指定的EventLoop中去执行
safeExecute(executor, new Runnable() {
@Override
public void run() {
// 回调监听器
notifyListenersNow();
}
});
}
private void notifyListenersNow() {
Object listeners;
synchronized (this) {
// Only proceed if there are listeners to notify and we are not already notifying listeners.
if (notifyingListeners || this.listeners == null) {
return;
}
notifyingListeners = true;
listeners = this.listeners;
this.listeners = null;
}
for (;;) {
// 条件成立:注册的监听器是DefaultFutureListeners类型
if (listeners instanceof DefaultFutureListeners) {
// 回调DefaultFutureListeners里面所有监听器的operationComplete方法
notifyListeners0((DefaultFutureListeners) listeners);
}
// 条件成立:说明监听器是GenericFutureListener类型
else {
// 回调这个GenericFutureListener监听器的operationComplete方法
notifyListener0(this, (GenericFutureListener<?>) listeners);
}
synchronized (this) {
if (this.listeners == null) {
// Nothing can throw from within this method, so setting notifyingListeners back to false does not need to be in a finally block.
notifyingListeners = false;
return;
}
listeners = this.listeners;
this.listeners = null;
}
}
}
/**
* 回调DefaultFutureListeners中所有的GenericFutureListener监听器的operationComplete方法
* @param listeners DefaultFutureListeners实例
*/
private void notifyListeners0(DefaultFutureListeners listeners) {
// 获取到DefaultFutureListeners中所有的GenericFutureListener类型的监听器
GenericFutureListener<?>[] a = listeners.listeners();
int size = listeners.size();
// 遍历所有的GenericFutureListener类型的监听器,回调它们的operationComplete方法
for (int i = 0; i < size; i ++) {
notifyListener0(this, a[i]);
}
}
/**
* 回调GenericFutureListener监听器的operationComplete方法
* @param future promise实例
* @param l 监听器实例
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static void notifyListener0(Future future, GenericFutureListener l) {
try {
l.operationComplete(future);
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationComplete()", t);
}
}
}
2.DefaultProgressivePromise
该类继承自DefaultPromise,在DefaultPromise的基础上添加了可以设置完成进度的功能,增强功能体现在ProgressivePromise接口
在原来的promise接口的基础上新增了setProgress方法和tryProgress方法,两个方法的参数分别表示任务已完成的进度和任务需要完成的总进度,并且当调用者两个方法的时候,会触发属于ProgressivePromise特有的监听器类型GenericProgressiveFutureListener
3.PromiseCombiner
该类是一个promise辅助类,它能够收集多个promise,在这些promise都完成之后去触发一个聚合的promise,应用场景可以是当有多个promise的时候,如果我们想要这些promise在完成之后去触发回调,那么这个类就是一个很好的选择。它提供了add和addAll方法收集需要被监控的promise,提供了finish方法收集聚合promise
收集需要被监控的promise:
public void add(Future future) {
checkAddAllowed();
checkInEventLoop();
++expectedCount;
future.addListener(listener);
}
该方法关键就是给每一个需要被监控的promise添加一个监听器,这个监听器具体做什么的呢
private final GenericFutureListener<Future<?>> listener = new GenericFutureListener<Future<?>>() {
@Override
public void operationComplete(final Future<?> future) {
if (executor.inEventLoop()) {
operationComplete0(future);
} else {
executor.execute(new Runnable() {
@Override
public void run() {
operationComplete0(future);
}
});
}
}
private void operationComplete0(Future<?> future) {
assert executor.inEventLoop();
++doneCount;
if (!future.isSuccess() && cause == null) {
cause = future.cause();
}
if (doneCount == expectedCount && aggregatePromise != null) {
tryPromise();
}
}
};
当promise完成之后就会调用operationComplete0方法,此时会判断这个promise是否是最后一个完成的promise,如果是的话就调用tryPromise方法
private boolean tryPromise() {
return (cause == null) ? aggregatePromise.trySuccess(null) : aggregatePromise.tryFailure(cause);
}
tryPromise方法做的就是会去通知聚合promise,如果被监控的promise集合中有一个是失败的,那么就会给聚合promise设置失败的异常,反之被监控的promise集合全部成功的话就会给聚合promise设置成功的结果值