8.Future&Promise

Future

最顶端的是 java.util.concurrent.Future 接口, 表示一个异步操作后的结果对象.

这里面有三个关键字: 异步, 操作, 结果.

首先, Future 首先是一个 “结果”; 其次这个结果产生于一个 “操作”, 操作具体是什么可以随便定义; 最后这个操作是 "异步" 执行的, 这就意味着 “操作” 可能在另一个线程中并发执行, 也可能随后在同一个线程中执行, 什么时候产生结果是一件不确定的事.

public interface Future<V> extends java.util.concurrent.Future<V> {
    // io 操作 成功完成返回 TRUE
    boolean isSuccess();

    // 当且仅当 io 操作 可以被方法 #cancel 取消的时候, 返回 TRUE
    boolean isCancellable();

    // 返回I/O操作的异常实例 - 如果I/O操作本身是成功的, 此方法返回null
    Throwable cause();

    // 为当前Future实例添加监听Future操作完成的监听器 - isDone()方法激活之后所有监听器实例会得到回调
    Future<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
    Future<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners);

    // 为当前Future移除监听Future操作完成的监听器
    Future<V> removeListener(GenericFutureListener<? extends Future<? super V>> listener);
    Future<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners);

    // 同步等待Future完成得到最终结果(成功) 或者抛出异常(失败), 响应中断
    Future<V> sync() throws InterruptedException;

    // 同步等待Future完成得到最终结果(成功) 或者抛出异常(失败), 不响应中断
    Future<V> syncUninterruptibly();

    // 等待Future完成, 响应中断
    Future<V> await() throws InterruptedException;

    // 等待Future完成, 不响应中断
    Future<V> awaitUninterruptibly();

    // 带超时时限的等待Future完成, 响应中断
    boolean await(long timeout, TimeUnit unit) throws InterruptedException;
    boolean await(long timeoutMillis) throws InterruptedException;

    // 带超时时限的等待Future完成, 不响应中断
    boolean awaitUninterruptibly(long timeout, TimeUnit unit);
    boolean awaitUninterruptibly(long timeoutMillis);

    // 非阻塞马上返回Future的结果, 如果Future未完成, 此方法一定返回null;
    // 有些场景下如果Future成功获取到的结果是null则需要二次检查isDone()方法是否为true
    V getNow();

    // 取消 io 操作, 参数 mayInterruptIfRunning 指定是否中断 io 操作线程
    // 如果取消成功会抛出CancellationException异常(并不是该方法抛出异常).
    @Override
    boolean cancel(boolean mayInterruptIfRunning);
}

sync()await() 方法类似, 只是 sync() 会检查异常执行的情况, 一旦发现执行异常马上把异常实例包装抛出, 而 await() 方法对异常无感知.

扩展了 JDK 中的 Future 有如下好处:

  • 更加简单的结果返回方式. 方便判断成功、失败 或 已取消 等状态.
  • 更加灵活的结果处理方式. JDK 中只提供了主动得到结果的 get 方法, 要么阻塞要么轮询. Netty 除了支持主动 get 方法外, 还可以使用 Listener 被动监听结果.

Netty 的 Future 最大的特点是增加了 Listener 被动接收任务完成通知, 下面是两个 Listener 接口的定义:

public interface GenericFutureListener<F extends Future<?>> extends EventListener {
    void operationComplete(F future) throws Exception;
}

public interface 
  GenericProgressiveFutureListener<F extends ProgressiveFuture<?>> extends GenericFutureListener<F> {
    void operationProgressed(F future, long progress, long total) throws Exception;
}

把一个 listener 添加到 future 之后. 当异步操作完成之后, listener 会被通知一次, 同时会回调 operationComplete 方法. 参数 future 是当前通知的 future, 这意味这, 一个 listener 可以被添加到多个 future 中.

当异步操作进度发送变化时, listener 会被通知, 同时会回调 operationProgressed 方法. progress 是当前进度, total是总进度. progress==total 表示操作完成. 如果不知道何时完成操作 progress=-1.

Promise

我们知道, JDK 并发包中的 Future 是不可写, 也没有提供可监听的入口, 而 Promise 很好地弥补了这两个问题.

io.netty.util.concurrent.Promise 在注释中只有一句话: 特殊的可写的 io.netty.util.concurrent.Future (Promise 接口是 io.netty.util.concurrent.Future 的子接口).

这里的 可写 指的是: 可以自定义 成功, 失败等信息.

值得注意的是: 下面接口新增了一下方法来设置值, 然后将 addListener 等方法的返回值设置为 Promise. 下面 其它属性和源码 有对这些接口的源码分析.

public interface Promise<V> extends Future<V> {

    // 标记当前Future成功, 设置结果, 如果设置成功, 则通知所有的监听器, 
    // 如果Future已经成功或者失败, 则抛出IllegalStateException
    Promise<V> setSuccess(V result);

    // 标记当前Future成功, 设置结果, 如果设置成功, 则通知所有的监听器并且返回true, 否则返回false
    boolean trySuccess(V result);

    // 标记当前Future失败, 设置结果为异常实例, 如果设置成功, 则通知所有的监听器, 
    // 如果Future已经成功或者失败, 则抛出IllegalStateException
    Promise<V> setFailure(Throwable cause);

    // 标记当前Future失败, 设置结果为异常实例, 如果设置成功, 则通知所有的监听器并且返回true, 否则返回false
    boolean tryFailure(Throwable cause);

    // 标记当前的Promise实例为不可取消, 设置成功返回true,否则返回false
    boolean setUncancellable();
}

DefaultPromise

另一方面从继承关系来看, DefaultPromise 是这些接口的最终实现类, 所以分析源码的时候需要把重心放在 DefaultPromise 类.

其实 DefaultPromise 还有很多子类, 某些实现是为了定制特定的场景做了扩展.

添加 Listener

上面说过最主要的就是监视器, 先从 监视器, addListener() 方法来说.

private Object listeners;
// DefaultPromise 类
public Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener) {
    checkNotNull(listener, "listener");
    // 并发控制, 保证多线程情况下只有一个线程执行添加操作
    synchronized (this) {
        addListener0(listener);
    }
    // 操作完成, 通知监听者
    if (isDone()) {
        notifyListeners();
    }

    return this;
}
// DefaultPromise 类
private void addListener0(GenericFutureListener<? extends Future<? super V>> listener) {
    // 第一次添加这里肯定是个 null
    if (listeners == null) {
        listeners = listener;
    // 如果你第一次添加的就是 DefaultFutureListeners 实例, 那么直接会 add
    } else if (listeners instanceof DefaultFutureListeners) {
        ((DefaultFutureListeners) listeners).add(listener);
    } else {
        // 如果 listeners 变量不是 DefaultFutureListeners 类型, 并想添加多个 Listener.
        // 那么就会创建 DefaultFutureListeners 实例.
        listeners = new DefaultFutureListeners((GenericFutureListener<?>) listeners, listener);
    }
}

也就是说单个 Listener 可以是 GenericFutureListener 类型, 而如果是多个 Listener 则就是 DefaultFutureListeners 类型. 也就是说 DefaultFutureListeners 类用于保存监听器实例数组.

// 这个构造相对特别, 是为了让 Promise 中的 listeners 实例由单个
// GenericFutureListener 实例转换为 DefaultFutureListeners 类型.
DefaultFutureListeners(
        GenericFutureListener<? extends Future<?>> first, 
        GenericFutureListener<? extends Future<?>> second) {
    listeners = new GenericFutureListener[2];
    listeners[0] = first;
    listeners[1] = second;
    size = 2;
    // 注意 progressiveSize 变量,
    // 只有是 GenericProgressiveFutureListener 类型时, 才会 +1
    if (first instanceof GenericProgressiveFutureListener) {
        progressiveSize ++;
    }
    if (second instanceof GenericProgressiveFutureListener) {
        progressiveSize ++;
    }
}

// DefaultFutureListeners 类
public void add(GenericFutureListener<? extends Future<?>> l) {
    GenericFutureListener<? extends Future<?>>[] listeners = this.listeners;
    final int size = this.size;
    // 注意这里, 每次扩容数组长度是原来的2倍
    if (size == listeners.length) {
        this.listeners = listeners = Arrays.copyOf(listeners, size << 1);
    }
    // 把当前的 GenericFutureListener 加入数组中
    listeners[size] = l;
    // 监听器总数量 +1
    this.size = size + 1;
    // 如果为 GenericProgressiveFutureListener, 则带进度指示的监听器总数量 +1
    if (l instanceof GenericProgressiveFutureListener) {
        progressiveSize ++;
    }
}

每添加一次 Listener 都会都会判断一次操作是否完成, 这里先不管 isDone 的用法, 主要看 notifyListenters() 方法.

// DefaultPromise 类
private void notifyListeners() {
    EventExecutor executor = executor();
    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;
        }
    }

    // 当前执行线程不是事件循环线程, 则把 notifyListenersNow() 包装为 Runnable 实例放到 EventExecutor 中执行.
    safeExecute(executor, new Runnable() {
        @Override
        public void run() {
            notifyListenersNow();
        }
    });
}

// 马上通知所有监听器进行回调
private void notifyListenersNow() {
    Object listeners;
    // 为了保证所有的 Listener 只通知一次, 并且保证 Listener 不会丢失.
    synchronized (this) {
        if (notifyingListeners || this.listeners == null) {
            return;
        }
        notifyingListeners = true;
        listeners = this.listeners;
        this.listeners = null;
    }
  
    for (;;) {
        // 如果是 DefaultFutureListeners 类型, 会使用 for 循环获取 Listener 后调用 notifyListener0 方法.
        // 否则直接调用 notifyListener0 方法.
        if (listeners instanceof DefaultFutureListeners) {
            notifyListeners0((DefaultFutureListeners) listeners);
        } else {
            notifyListener0(this, (GenericFutureListener<?>) listeners);
        }
        // 这里在判断一次, 因为有可能又添加了 Listener,
        // 所以需要再调用新添加的, 直到没有 Listener 为止.
        synchronized (this) {
            if (this.listeners == null) {
                notifyingListeners = false;
                return;
            }
            listeners = this.listeners;
            this.listeners = null;
        }
    }
}

移除 Listener

如果想移除一个或多个 Listener 则可以使用 removeListener 方法.

// DefaultPromise 类
private void removeListener0(GenericFutureListener<? extends Future<? super V>> listener) {
    // 如果当前 Promise 实例持有 listeners 的是 DefaultFutureListeners 类型, 则调用它的 remove() 方法进行移除.
    if (listeners instanceof DefaultFutureListeners) {
        ((DefaultFutureListeners) listeners).remove(listener);
    } else if (listeners == listener) {
        // 如果当前 Promise 实例持有 listeners 不为 DefaultFutureListeners 类型,
        // 也就是单个 GenericFutureListener 并且和传入的 listener 相同, 则 Promise 实例持有 listeners 置为 null.
        listeners = null;
    }
}

// DefaultFutureListeners 类
public void remove(GenericFutureListener<? extends Future<?>> l) {
    final GenericFutureListener<? extends Future<?>>[] listeners = this.listeners;
    int size = this.size;
    for (int i = 0; i < size; i ++) {
        if (listeners[i] == l) {
            // 计算需要需要移动的监听器的下标
            int listenersToMove = size - i - 1;
            if (listenersToMove > 0) {
                // listenersToMove 后面的元素全部移动到数组的前端
                System.arraycopy(listeners, i + 1, listeners, i, listenersToMove);
            }
            // 当前监听器总量的最后一个位置设置为 null, 数量 -1
            listeners[-- size] = null;
            this.size = size;
            // 如果监听器是 GenericProgressiveFutureListener, 则带进度指示的监听器总数量 -1
            if (l instanceof GenericProgressiveFutureListener) {
                progressiveSize --;
            }
            return;
        }
    }
}

移除的时候并不会调用 notifyListeners() 方法.

其它属性和源码

setSuccess

/**
 * 标记当前 Future 成功.
 *
 * 还有一个类似方法 trySuccess, 只不过该方法不会抛出异常; 当然该方法内部也是调用 setSuccess0 方法.
 */
public Promise<V> setSuccess(V result) {
    if (setSuccess0(result)) {
        return this;
    }
    // 设置失败说明了多次设置, Promise 已经执行完毕, 则抛出异常.
    throw new IllegalStateException("complete already: " + this);
}

/**
 * 设置执行成功的结果,如果入参result为null,则选用SUCCESS属性,否则使用result
 */
private static final Object SUCCESS = new Object();
private static final Object UNCANCELLABLE = new Object();
private boolean setSuccess0(V result) {
    return setValue0(result == null ? SUCCESS : result);
}

// 该变量默认为 null
private volatile Object result;
private boolean setValue0(Object objResult) {
    // CAS 更新 result 变量的值为传递的参数,
    // result 变量的值, 只有为 null 或者 UNCANCELLABLE(无法取消) 才能更新成功.
    if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
        RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
        // 为什么这里会出现等待线程?
        // 因为有可能调用了 await 或 sync 方法.
        if (checkNotifyWaiters()) {
            // 该方法在之前已经说了
            notifyListeners();
        }
        return true;
    }
    return false;
}

private synchronized boolean checkNotifyWaiters() {
    // 如果有等待线程则调用 Object#notifyAll() 唤醒所有等待线程
    if (waiters > 0) {
        notifyAll();
    }
    // 如果 listeners 不为空(也就是存在监听器) 的时候才返回 true
    return listeners != null;
}

setFailure

/**
 * 标记当前 Future 失败.
 *
 * 与 setSuccess 相似, 都有 抛异常 和 不抛异常(tryFailure) 的方法.
 */
public Promise<V> setFailure(Throwable cause) {
    if (setFailure0(cause)) {
        return this;
    }
    throw new IllegalStateException("complete already: " + this, cause);
}

private boolean setFailure0(Throwable cause) {
    // setValue0 方法上面说了, 只是会将 Throwable 包装成 CauseHolder.
    return setValue0(new CauseHolder(checkNotNull(cause, "cause")));
}

setUncancellable

/**
 * 当前的 Promise 实例为不可取消.
 * 值得注意的是: 当任务被执行就会设置为不可取消.
 */
public boolean setUncancellable() {
    // 通过 CAS 将 result 值更新为 UNCANCELLABLE(不可取消), 旧值必须为 null, 如果成功则返回 true
    if (RESULT_UPDATER.compareAndSet(this, null, UNCANCELLABLE)) {
        return true;
    }
    Object result = this.result;
    // isDone0() 和 isCancelled0() 都是终态, 这里如果命中终态就返回 false.
    // 还可以理解为, 这里 result 不能为null, 如果不为终态, 它只能是 UNCANCELLABLE 属性实例
    return !isDone0(result) || !isCancelled0(result);
}
// 判断是否完成, 依据是 result 不为 null 并且不为 UNCANCELLABLE(不可取消) 才为完成.
private static boolean isDone0(Object result) {
    return result != null && result != UNCANCELLABLE;
}
// 判断是否取消, 依据是 result 必须是 CauseHolder 类型,
// 同时 CauseHolder 中的 cause 属性必须为 CancellationException 类型或者其子类.
private static boolean isCancelled0(Object result) {
    return result instanceof CauseHolder && 
           ((CauseHolder) result).cause instanceof CancellationException;
}

await

// 等待获取结果的线程数量
// 如果在多个线程中调用 await() 方法, 没调用一次该值就会 +1.
private short waiters;

/**
 * 该方法会无限等待 Future 完成, 如果线程被中断会抛出 InterruptedException 异常.
 */
public Promise<V> await() throws InterruptedException {
    // 判断是否完成, result != null && result != UNCANCELLABLE(不可取消)
    if (isDone()) {
        return this;
    }

    /**
     * 如果调用了 Thread#interrupt() 方法, 线程被打上中断标记.
     * Thread.interrupted() 就会返回 true, 表示当前线程已经中断.
     * 值得注意的是: interrupted() 会清除中断标记, 也就是说第二次执行, 该方法会返回 false.
     */
    if (Thread.interrupted()) {
        throw new InterruptedException(toString());
    }

    // 检查死锁, 就是为了保证 await() 方法是在另一个线程中调用.
    checkDeadLock();

    synchronized (this) {
        while (!isDone()) {
            // waiters 变量值 +1, 如果该值等于 short 类型最大值(32767), 则会抛出 IllegalStateException.
            incWaiters();
            try {
                // 这里调用的是 Object#wait() 方法进行等待, 如果线程被中断会抛出 InterruptedException.
                // 值得注意的是: Object#wait() 方法会释放锁, 让别的线程争夺锁后执行该同步代码块.
                // 这里进行等待后, 什么时候唤醒?
                //   1. 调用 setSuccess 和 setFailure.
                //   2. 调用 cancel 取消操作.
                wait();
            } finally {
                // waiters 变量值 -1
                decWaiters();
            }
        }
    }
    return this;
}

await() 方法还有两个重载方法, 这两个重载方法可以指定超时时间, 但最终都会调用私有方法 DefaultPromise#await0.

private Boolean await0(long timeoutNanos, Boolean interruptable) throws InterruptedException {
    // 判断是否完成, result != null && result != UNCANCELLABLE(不可取消)
    if (isDone()) {
        return true;
    }
    // 如果超时时限小于 0 那么返回 isDone() 的结果.
    if (timeoutNanos <= 0) {
        return isDone();
    }
  
    // 如果允许中断, 当前线程的中断标志位为 true, 则抛出 InterruptedException.
    if (interruptable && Thread.interrupted()) {
        throw new InterruptedException(toString());
    }
  
    // 检查死锁, 就是为了保证 await() 方法是在另一个线程中调用.
    checkDeadLock();
  
    long startTime = System.nanoTime();
    long waitTime = timeoutNanos;
    Boolean interrupted = false;
    try {
        for (;;) {
            synchronized (this) {
                if (isDone()) {
                    return true;
                }
                incWaiters();
                try {
                    // 这里调用的是带超时时限的 Object#wait() 方法进行等待
                    wait(waitTime / 1000000, (int) (waitTime % 1000000));
                }
                catch (InterruptedException e) {
                    // 如果允许中断则抛出异常, 那么直接抛出 InterruptedException.
                    if (interruptable) {
                        throw e;
                    } else {
                        // 否则只记录中断过的状态
                        interrupted = true;
                    }
                }
                finally {
                    decWaiters();
                }
            }
            if (isDone()) {
                return true;
            } else {
                // 步入这里说明 Promise 尚未执行完毕, 则重新计算等待时间间隔的长度数量(修正), 
                // 如果大于 0 则进入下一轮循环.
                waitTime = timeoutNanos - (System.nanoTime() - startTime);
                if (waitTime <= 0) {
                    return isDone();
                }
            }
        }
    }
    finally {
        // 如果线程被中断跳出等待阻塞, 则清除线程的中断标志位
        if (interrupted) {
            Thread.currentThread().interrupt();
        }
    }
}

awaitUninterruptibly() 方法与 await() 方法, 实现类似, 只不过该方法不响应中断. 也就是会捕获 InterruptedException 异常, 然后将 interrupted 设置为 true, 然后调用 Thread.currentThread().interrupt(); 来取消中断标记.

对于带有超时时间的 awaitUninterruptibly() 方法, 内部同样会调用 await0, 只不过参数二为 false.

sync

// 同步等待 Future 完成得到最终结果(成功) 或者抛出异常(失败), 响应中断.
public Promise<V> sync() throws InterruptedException {
  // 该方法上面有说.
	await();
  // 主要看一下这个方法.
	rethrowIfFailed();
	return this;
}

// 同步等待 Future 完成得到最终结果(成功) 或者抛出异常(失败), 不响应中断.
public Promise<V> syncUninterruptibly() {
  // 该方法上面有说.
	awaitUninterruptibly();
  // 主要看一下这个方法.
	rethrowIfFailed();
	return this;
}

// cause 不为 null 则抛出
private void rethrowIfFailed() {
  // 返回 IO 操作的异常实例.
	Throwable cause = cause();
	if (cause == null) {
		return;
	}
  // 如果有异常, 则抛出异常.
	PlatformDependent.throwException(cause);
}

syncawait 方法类似, 区别就是 sync 方法会抛出失败原因.

因为 isDone 方法判断操作是否完成是根据 result != null && result != UNCANCELLABLE, 并不会判断有没有异常.

杂项

/**
 * IO 操作是否完成
 */
public boolean isSuccess() {
    Object result = this.result;
    // result 值不能为 null 不能为 UNCANCELLABLE(不可取消), 还有就是不能为 CauseHolder 类型.
    // 因为失败原因会被封装为 CauseHolder 实例.
    return result != null && result != UNCANCELLABLE && !(result instanceof CauseHolder);
}

/**
 * IO 操作 可以被 #cancel 取消.
 */
public boolean isCancellable() {
    // 就是说 result 没有值, 说明现在是无状态(成功, 失败或已取消)的. 
    return result == null;
}

/**
 * 取消 io 操作, 参数 mayInterruptIfRunning 指定是否中断 io 操作线程.
 * 值得注意的是: 任务执行后 result 的值为 UNCANCELLABLE(不可取消).
 */
public boolean cancel(boolean mayInterruptIfRunning) {
    // 通过 CAS 更新 result 值为 CANCELLATION_CAUSE_HOLDER, result 的值必须为 null.
    if (RESULT_UPDATER.compareAndSet(this, null, CANCELLATION_CAUSE_HOLDER)) {
        // 唤醒所有等待的线程, 后通知监听器.
        if (checkNotifyWaiters()) {
            notifyListeners();
        }
        return true;
    }
    return false;
}

/**
 * 返回 IO 操作的异常实例 - 如果I/O操作本身是成功的, 此方法返回null
 */
public Throwable cause() {
    return cause0(result);
}
private Throwable cause0(Object result) {
    // 在设置 io 失败时, 会将失败信息封装为 CauseHolder 实例,
    // 如果 result 值不是 CauseHolder 实例, 那么肯定是成功的.
    // 值得注意的是: 失败 和 已取消 也都属于 已完成 状态.
    if (!(result instanceof CauseHolder)) {
        return null;
    }
    // 如果 result 的值为 CANCELLATION_CAUSE_HOLDER, 说明该任务被主动取消.
    if (result == CANCELLATION_CAUSE_HOLDER) {
        // 该类保存了 CANCELLATION_CAUSE_HOLDER 栈信息, 重写了 toString 方法.
        CancellationException ce = new LeanCancellationException();
        /**
         * 正常情况下, 该值肯定会被修改成功.
         * 这里再进行一次 CAS 操作, 个人认为可以是怕通过反射修改了 result 的值.
         */
        if (RESULT_UPDATER.compareAndSet(this, CANCELLATION_CAUSE_HOLDER, new CauseHolder(ce))) {
            return ce;
        }
        result = this.result;
    }
    return ((CauseHolder) result).cause;
}

// 判断 Promise 实例是否取消.
public Boolean isCancelled() {
    return isCancelled0(result);
}

// 判断Promise实例是否完成
public Boolean isDone() {
    return isDone0(result);
}

DefaultChannelPromise

关于 ChannelFutureChannelPromise 接口, 只是增加了一个主要的方法 Channel channel();; 而且修改了其它方法的返回值类型, 为对应的接口类型.

虽然 DefaultChannelPromise 实现了这两个接口, 但是同时也继承了 DefaultPromise, 也就是说该类对接口的实现基本上都是调用父级的实现.

该类重写了 executor() 方法, 当 DefaultPromise 没有指定 executor 时, 会获取 Channel 对应的 executor.

讨论

1.什么情况下才会设置为无法取消?
当任务被执行时, 就会设置为 无法取消.

2.如果任务刚开始执行后调用 setSuccess 或 setFailure 方法, 那么该任务会怎样?
首先, 该任务并不会因为主动调用了这两个方法而停止执行.
只不过会立即回调 Listener, 但是 Listener 的回调, 是在另一个线程中还是在当前线程中?

参考资料

从源码上理解Netty并发工具-Promise

posted @ 2020-08-18 16:53  scikstack  阅读(162)  评论(0编辑  收藏  举报