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

2021-04-25 02:27

阅读:351

标签:compare   递归调用   个人   操作   特定   原因   并发包   rup   说明   

前提

最近一直在看Netty相关的内容,也在编写一个轻量级的RPC框架来练手,途中发现了Netty的源码有很多亮点,某些实现甚至可以用苛刻来形容。另外,Netty提供的工具类也是相当优秀,可以开箱即用。这里分析一下个人比较喜欢的领域,并发方面的一个Netty工具模块 - Promise

技术图片

环境版本:

  • Netty:4.1.44.Final
  • JDK1.8

Promise简介

Promise,中文翻译为承诺或者许诺,含义是人与人之间,一个人对另一个人所说的具有一定憧憬的话,一般是可以实现的。

io.netty.util.concurrent.Promise在注释中只有一句话:特殊的可写的io.netty.util.concurrent.FuturePromise接口是io.netty.util.concurrent.Future的子接口)。而io.netty.util.concurrent.Futurejava.util.concurrent.Future的扩展,表示一个异步操作的结果。我们知道,JDK并发包中的Future是不可写,也没有提供可监听的入口(没有应用观察者模式),而Promise很好地弥补了这两个问题。另一方面从继承关系来看,DefaultPromise是这些接口的最终实现类,所以分析源码的时候需要把重心放在DefaultPromise类。一般一个模块提供的功能都由接口定义,这里分析一下两个接口的功能列表:

  • io.netty.util.concurrent.Promise
  • io.netty.util.concurrent.Future

先看io.netty.util.concurrent.Future接口:

public interface Future extends java.util.concurrent.Future {

    // I/O操作是否执行成功
    boolean isSuccess();

    // 标记是否可以通过下面的cancel(boolean mayInterruptIfRunning)取消I/O操作
    boolean isCancellable();

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

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

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

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

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

    // 等待Future完成,不响应中断
    Future 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();

    // 取消当前Future实例的执行,如果取消成功会抛出CancellationException异常
    @Override
    boolean cancel(boolean mayInterruptIfRunning);
}

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

接着看io.netty.util.concurrent.Promise接口:

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

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

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

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

    // 下面的方法和io.netty.util.concurrent.Future中的方法基本一致,只是修改了返回类型为Promise

    @Override
    Promise addListener(GenericFutureListener extends Future super V>> listener);

    @Override
    Promise addListeners(GenericFutureListener extends Future super V>>... listeners);

    @Override
    Promise removeListener(GenericFutureListener extends Future super V>> listener);

    @Override
    Promise removeListeners(GenericFutureListener extends Future super V>>... listeners);

    @Override
    Promise await() throws InterruptedException;

    @Override
    Promise awaitUninterruptibly();

    @Override
    Promise sync() throws InterruptedException;

    @Override
    Promise syncUninterruptibly();
}

到此,Promise接口的所有功能都分析完毕,接下来从源码角度详细分析Promise的实现。

Promise源码实现

Promise的实现类为io.netty.util.concurrent.DefaultPromise(其实DefaultPromise还有很多子类,某些实现是为了定制特定的场景做了扩展),而DefaultPromise继承自io.netty.util.concurrent.AbstractFuture

public abstract class AbstractFuture implements Future {

    // 永久阻塞等待获取结果的方法
    @Override
    public V get() throws InterruptedException, ExecutionException {
        // 调用响应中断的永久等待方法进行阻塞
        await();
        // 从永久阻塞中唤醒后,先判断Future是否执行异常
        Throwable cause = cause();
        if (cause == null) {
            // 异常为空说明执行成功,调用getNow()方法返回结果
            return getNow();
        }
        // 异常为空不为空,这里区分特定的取消异常则转换为CancellationException抛出
        if (cause instanceof CancellationException) {
            throw (CancellationException) cause;
        }
        // 非取消异常的其他所有异常都被包装为执行异常ExecutionException抛出
        throw new ExecutionException(cause);
    }
    
    // 带超时阻塞等待获取结果的方法
    @Override
    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        // 调用响应中断的带超时时限等待方法进行阻塞
        if (await(timeout, unit)) {
             // 从带超时时限阻塞中唤醒后,先判断Future是否执行异常
            Throwable cause = cause();
            if (cause == null) {
                // 异常为空说明执行成功,调用getNow()方法返回结果
                return getNow();
            }
            // 异常为空不为空,这里区分特定的取消异常则转换为CancellationException抛出
            if (cause instanceof CancellationException) {
                throw (CancellationException) cause;
            }
            // 在非等待超时的前提下,非取消异常的其他所有异常都被包装为执行异常ExecutionException抛出
            throw new ExecutionException(cause);
        }
        // 方法步入此处说明等待超时,则抛出超时异常TimeoutException
        throw new TimeoutException();
    }
}

AbstractFuture仅仅对get()get(long timeout, TimeUnit unit)两个方法进行了实现,其实这两处的实现和java.util.concurrent.FutureTask中的实现方式十分相似。

DefaultPromise的源码比较多,这里分开多个部分去阅读,先看它的属性和构造函数:

public class DefaultPromise extends AbstractFuture implements Promise {

    // 正常日志的日志句柄,InternalLogger是Netty内部封装的日志接口
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultPromise.class);

    // 任务拒绝执行时候的日志句柄 - Promise需要作为一个任务提交到线程中执行,如果任务拒绝则使用此日志句柄打印日志
    private static final InternalLogger rejectedExecutionLogger =
            InternalLoggerFactory.getInstance(DefaultPromise.class.getName() + ".rejectedExecution");

    // 监听器的最大栈深度,默认值为8,这个值是防止嵌套回调调用的时候栈深度过大导致内存溢出,后面会举个例子说明它的用法
    private static final int MAX_LISTENER_STACK_DEPTH = Math.min(8,
            SystemPropertyUtil.getInt("io.netty.defaultPromise.maxListenerStackDepth", 8));
    
    // 结果更新器,用于CAS更新结果result的值
    @SuppressWarnings("rawtypes")
    private static final AtomicReferenceFieldUpdater RESULT_UPDATER =
            AtomicReferenceFieldUpdater.newUpdater(DefaultPromise.class, Object.class, "result");
    
    // 用于填充result的值,当设置结果result传入null,Promise执行成功,用这个值去表示成功的结果
    private static final Object SUCCESS = new Object();
    
    // 用于填充result的值,表示Promise不能被取消
    private static final Object UNCANCELLABLE = new Object();
    
    // CancellationException实例的持有器,用于判断Promise取消状态和抛出CancellationException
    private static final CauseHolder CANCELLATION_CAUSE_HOLDER = new CauseHolder(ThrowableUtil.unknownStackTrace(
            new CancellationException(), DefaultPromise.class, "cancel(...)"));
    
    // CANCELLATION_CAUSE_HOLDER的异常栈信息元素数组
    private static final StackTraceElement[] CANCELLATION_STACK = CANCELLATION_CAUSE_HOLDER.cause.getStackTrace();
    
    // 真正的结果对象,使用Object类型,最终有可能为null、真正的结果实例、SUCCESS、UNCANCELLABLE或者CANCELLATION_CAUSE_HOLDER等等
    private volatile Object result;
    
    // 事件执行器,这里暂时不做展开,可以理解为单个调度线程
    private final EventExecutor executor;
    
     // 监听器集合,可能是单个GenericFutureListener实例或者DefaultFutureListeners(监听器集合)实例
    private Object listeners;
    
    // 等待获取结果的线程数量
    private short waiters;

    // 标记是否正在回调监听器
    private boolean notifyingListeners;

    // 构造函数依赖于EventExecutor
    public DefaultPromise(EventExecutor executor) {
        this.executor = checkNotNull(executor, "executor");
    }

    protected DefaultPromise() {
        // only for subclasses - 这个构造函数预留给子类
        executor = null;
    }

    // ... 省略其他代码 ...

    // 私有静态内部类,用于存放Throwable实例,也就是持有异常的原因实例
    private static final class CauseHolder {
        final Throwable cause;
        CauseHolder(Throwable cause) {
            this.cause = cause;
        }
    }

    // 私有静态内部类,用于覆盖CancellationException的栈信息为前面定义的CANCELLATION_STACK,同时覆盖了toString()返回CancellationException的全类名
    private static final class LeanCancellationException extends CancellationException {
        private static final long serialVersionUID = 2794674970981187807L;

        @Override
        public Throwable fillInStackTrace() {
            setStackTrace(CANCELLATION_STACK);
            return this;
        }

        @Override
        public String toString() {
            return CancellationException.class.getName();
        }
    }
    // ... 省略其他代码 ...
}

Promise目前支持两种类型的监听器:

  • GenericFutureListener:支持泛型的Future监听器。
  • GenericProgressiveFutureListener:它是GenericFutureListener的子类,支持进度表示和支持泛型的Future监听器(有些场景需要多个步骤实现,类似于进度条那样)。
// GenericFutureListener
public interface GenericFutureListener> extends EventListener {

    void operationComplete(F future) throws Exception;
}

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

为了让Promise支持多个监听器,Netty添加了一个默认修饰符修饰的DefaultFutureListeners类用于保存监听器实例数组:

// DefaultFutureListeners
final class DefaultFutureListeners {

    private GenericFutureListener extends Future>>[] listeners;
    private int size;
    private int progressiveSize; // the number of progressive listeners
    
    // 这个构造相对特别,是为了让Promise中的listeners(Object类型)实例由单个GenericFutureListener实例转换为DefaultFutureListeners类型
    @SuppressWarnings("unchecked")
    DefaultFutureListeners(GenericFutureListener extends Future>> first, GenericFutureListener extends Future>> second) {
        listeners = new GenericFutureListener[2];
        listeners[0] = first;
        listeners[1] = second;
        size = 2;
        if (first instanceof GenericProgressiveFutureListener) {
            progressiveSize ++;
        }
        if (second instanceof GenericProgressiveFutureListener) {
            progressiveSize ++;
        }
    }

    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 > l) {
        final GenericFutureListener extends Future>>[] listeners = this.listeners;
        int size = this.size;
        for (int i = 0; i  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;
            }
        }
    }
    
    // 返回监听器实例数组
    public GenericFutureListener extends Future>>[] listeners() {
        return listeners;
    }
    
    // 返回监听器总数量
    public int size() {
        return size;
    }
    
    // 返回带进度指示的监听器总数量
    public int progressiveSize() {
        return progressiveSize;
    }
}

接下来看DefaultPromise的剩余方法实现,笔者觉得DefaultPromise方法实现在代码顺序上是有一定的艺术的。先看几个判断Promise执行状态的方法:

public class DefaultPromise extends AbstractFuture implements Promise {

    // ... 省略其他代码 ...

    @Override
    public boolean setUncancellable() {
        // 通过结果更新器CAS更新result为UNCANCELLABLE,期望旧值为null,更新值为UNCANCELLABLE属性,如果成功则返回true
        if (RESULT_UPDATER.compareAndSet(this, null, UNCANCELLABLE)) {
            return true;
        }
        Object result = this.result;
        // 步入这里说明result当前值不为null,isDone0()和isCancelled0()都是终态,这里如果命中终态就返回false
        //(笔者注:其实可以这样认为,这里result不能为null,如果不为终态,它只能是UNCANCELLABLE属性实例)
        return !isDone0(result) || !isCancelled0(result);
    }

    @Override
    public boolean isSuccess() {
        Object result = this.result;
        // 如果执行成功,则结果不为null,同时不为UNCANCELLABLE,同时不为CauseHolder类型
        //(笔者注:其实可以这样认为,Promise为成功,则result只能是一个开发者定义的实例或者SUCCESS属性实例)
        return result != null && result != UNCANCELLABLE && !(result instanceof CauseHolder);
    }

    @Override
    public boolean isCancellable() {
        // 是否可取消的,result为null说明Promise处于初始化状态尚未执行,则认为可以取消
        return result == null;
    }

    @Override
    public Throwable cause() {
        // 通过当前result获取Throwable实例
        return cause0(result);
    }

    private Throwable cause0(Object result) {
        // result非CauseHolder类型,则直接返回null
        if (!(result instanceof CauseHolder)) {
            return null;
        }
        // 如果result为CANCELLATION_CAUSE_HOLDER(静态CancellationException的持有)
        if (result == CANCELLATION_CAUSE_HOLDER) {
            // 则新建一个自定义LeanCancellationException实例
            CancellationException ce = new LeanCancellationException();
            // 如果CAS更新结果result为LeanCancellationException新实例则返回
            if (RESULT_UPDATER.compareAndSet(this, CANCELLATION_CAUSE_HOLDER, new CauseHolder(ce))) {
                return ce;
            }
            // 走到这里说明了result是非CANCELLATION_CAUSE_HOLDER的自定义CauseHolder实例
            result = this.result;
        }
        // 兜底返回CauseHolder持有的cause
        return ((CauseHolder) result).cause;
    }
      
    // 静态方法,判断Promise是否为取消,依据是result必须是CauseHolder类型,同时CauseHolder中的cause必须为CancellationException类型或者其子类
    private static boolean isCancelled0(Object result) {
        return result instanceof CauseHolder && ((CauseHolder) result).cause instanceof CancellationException;
    }
    
    // 静态方法,判断Promise是否完成,依据是result不为null同时不为UNCANCELLABLE属性实例
    private static boolean isDone0(Object result) {
        return result != null && result != UNCANCELLABLE;
    }

    // 判断Promise实例是否取消
    @Override
    public boolean isCancelled() {
        return isCancelled0(result);
    }
    
    // 判断Promise实例是否完成
    @Override
    public boolean isDone() {
        return isDone0(result);
    }
    // ... 省略其他代码 ...
}    

接着看监听器的添加和移除方法(这其中也包含了通知监听器的逻辑):

public class DefaultPromise extends AbstractFuture implements Promise {

    // ... 省略其他代码 ...
    @Override
    public Promise addListener(GenericFutureListener extends Future super V>> listener) {
        // 入参非空校验
        checkNotNull(listener, "listener");
        // 加锁,锁定的对象是Promise实例自身
        synchronized (this) {
            // 添加监听器
            addListener0(listener);
        }
        // 如果Promise实例已经执行完毕,则通知监听器进行回调
        if (isDone()) {
            notifyListeners();
        }
        return this;
    }

    @Override
    public Promise addListeners(GenericFutureListener extends Future super V>>... listeners) {
        // 入参非空校验
        checkNotNull(listeners, "listeners");
        // 加锁,锁定的对象是Promise实例自身
        synchronized (this) {
            // 遍历入参数组添加监听器,有空元素直接跳出
            for (GenericFutureListener extends Future super V>> listener : listeners) {
                if (listener == null) {
                    break;
                }
                addListener0(listener);
            }
        }
        // 如果Promise实例已经执行完毕,则通知监听器进行回调
        if (isDone()) {
            notifyListeners();
        }

        return this;
    }

    @Override
    public Promise removeListener(final GenericFutureListener extends Future super V>> listener) {
        // 入参非空校验
        checkNotNull(listener, "listener");
        // 加锁,锁定的对象是Promise实例自身
        synchronized (this) {
            // 移除监听器
            removeListener0(listener);
        }
        return this;
    }

    @Override
    public Promise removeListeners(final GenericFutureListener extends Future super V>>... listeners) {
        // 入参非空校验
        checkNotNull(listeners, "listeners");
        // 加锁,锁定的对象是Promise实例自身
        synchronized (this) {
            // 遍历入参数组移除监听器,有空元素直接跳出
            for (GenericFutureListener extends Future super V>> listener : listeners) {
                if (listener == null) {
                    break;
                }
                removeListener0(listener);
            }
        }
        return this;
    }

    private void addListener0(GenericFutureListener extends Future super V>> listener) {
        // 如果Promise实例持有listeners为null,则直接设置为入参listener
        if (listeners == null) {
            listeners = listener;
        } else if (listeners instanceof DefaultFutureListeners) {
             // 如果当前Promise实例持有listeners的是DefaultFutureListeners类型,则调用它的add()方法进行添加
            ((DefaultFutureListeners) listeners).add(listener);
        } else {
            // 步入这里说明当前Promise实例持有listeners为单个GenericFutureListener实例,需要转换为DefaultFutureListeners实例
            listeners = new DefaultFutureListeners((GenericFutureListener>) listeners, listener);
        }
    }

    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;
        }
    }

    private void notifyListeners() {
        EventExecutor executor = executor();
        // 当前执行线程是事件循环线程,那么直接同步调用,简单来说就是调用notifyListeners()方法的线程和EventExecutor是同一个线程
        if (executor.inEventLoop()) {
            // 下面的ThreadLocal和listenerStackDepth是调用栈深度保护相关,博文会另起一个章节专门讲解这个问题,这里可以暂时忽略
            final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
            final int stackDepth = threadLocals.futureListenerStackDepth();
            if (stackDepth ) listeners);
            }
            synchronized (this) {
                if (this.listeners == null) {
                    // 这里因为没有异常抛出的可能,不用在finally块中编写,重置notifyingListeners为false并且返回跳出循环
                    notifyingListeners = false;
                    return;
                }
                  // 临时变量listeners存放瞬时的监听器实例,回调操作判断是基于临时实例去做 - 这里可能由另一个线程更新了listeners的值
                listeners = this.listeners;
                // 重置当前Promise实例的listeners为null,确保监听器只会被回调一次,下一次跳出for死循环
                this.listeners = null;
            }
        }
    }
   
    // 遍历DefaultFutureListeners中的listeners数组,调用静态方法notifyListener0()
    private void notifyListeners0(DefaultFutureListeners listeners) {
        GenericFutureListener>[] a = listeners.listeners();
        int size = listeners.size();
        for (int i = 0; i 

然后看wait()sync()方法体系:

public class DefaultPromise extends AbstractFuture implements Promise {

    // ... 省略其他代码 ...

    @Override
    public Promise await() throws InterruptedException {
        // 如果Promise执行完毕,直接返回
        if (isDone()) {
            return this;
        }
        // 如果当前线程中断则直接抛出InterruptedException
        if (Thread.interrupted()) {
            throw new InterruptedException(toString());
        }
        // 死锁检测
        checkDeadLock();
        // 加锁,加锁对象是当前Promise实例
        synchronized (this) {
            // 这里设置一个死循环,终止条件是isDone()为true
            while (!isDone()) {
                // 等待线程数加1
                incWaiters();
                try {
                    // 这里调用的是Object#wait()方法进行阻塞,如果线程被中断会抛出InterruptedException
                    wait();
                } finally {
                    // 解除阻塞后等待线程数减1
                    decWaiters();
                }
            }
        }
        return this;
    }

    @Override
    public Promise awaitUninterruptibly() {
        // 如果Promise执行完毕,直接返回
        if (isDone()) {
            return this;
        }
        // 死锁检测
        checkDeadLock();
        boolean interrupted = false;
        // 加锁,加锁对象是当前Promise实例
        synchronized (this) {
            // 这里设置一个死循环,终止条件是isDone()为true
            while (!isDone()) {
                 // 等待线程数加1
                incWaiters();
                try {
                    // 这里调用的是Object#wait()方法进行阻塞,捕获了InterruptedException异常,如果抛出InterruptedException记录线程的中断状态到interrupted
                    wait();
                } catch (InterruptedException e) {
                    // Interrupted while waiting.
                    interrupted = true;
                } finally {
                    // 解除阻塞后等待线程数减1
                    decWaiters();
                }
            }
        }
        // 如果线程被中断跳出等待阻塞,则清除线程的中断标志位
        if (interrupted) {
            Thread.currentThread().interrupt();
        }
        return this;
    }

    // 后面的几个带超时时限的wait()方法都是调用await0()

    @Override
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        return await0(unit.toNanos(timeout), true);
    }

    @Override
    public boolean await(long timeoutMillis) throws InterruptedException {
        return await0(MILLISECONDS.toNanos(timeoutMillis), true);
    }

    @Override
    public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
        try {
            return await0(unit.toNanos(timeout), false);
        } catch (InterruptedException e) {
            // Should not be raised at all.
            throw new InternalError();
        }
    }

    @Override
    public boolean awaitUninterruptibly(long timeoutMillis) {
        try {
            return await0(MILLISECONDS.toNanos(timeoutMillis), false);
        } catch (InterruptedException e) {
            // Should not be raised at all.
            throw new InternalError();
        }
    }
    
    // 检查死锁,这里判断了等待线程是事件循环线程则直接抛出BlockingOperationException异常
    // 简单来说就是:Promise的执行线程和等待结果的线程,不能是同一个线程,否则依赖会成环
    protected void checkDeadLock() {
        EventExecutor e = executor();
        if (e != null && e.inEventLoop()) {
            throw new BlockingOperationException(toString());
        }
    }

    @Override
    public Promise sync() throws InterruptedException {
        // 同步永久阻塞等待
        await();
        // 阻塞等待解除,如果执行存在异常,则直接抛出
        rethrowIfFailed();
        return this;
    }

    @Override
    public Promise syncUninterruptibly() {
        // 同步永久阻塞等待 - 响应中断
        awaitUninterruptibly();
        // 塞等待解除,如果执行存在异常,则直接抛出
        rethrowIfFailed();
        return this;
    }
    
    // waiters加1,如果超过Short.MAX_VALUE则抛出IllegalStateException
    private void incWaiters() {
        if (waiters == Short.MAX_VALUE) {
            throw new IllegalStateException("too many waiters: " + this);
        }
        ++waiters;
    }
    
    // waiters减1
    private void decWaiters() {
        --waiters;
    }
    
    // cause不为null则抛出
    private void rethrowIfFailed() {
        Throwable cause = cause();
        if (cause == null) {
            return;
        }
        PlatformDependent.throwException(cause);
    }

    private boolean await0(long timeoutNanos, boolean interruptable) throws InterruptedException {
        // 如果Promise执行完毕,直接返回
        if (isDone()) {
            return true;
        }
        // 如果超时时限小于0那么返回isDone()的结果
        if (timeoutNanos 

最后是几个设置结果和获取结果的方法:

public class DefaultPromise extends AbstractFuture implements Promise {

    // ... 省略其他代码 ...
    @Override
    public Promise setSuccess(V result) {
        // 设置成功结果,如果设置成功则返回当前Promise实例
        if (setSuccess0(result)) {
            return this;
        }
        // 设置失败说明了多次设置,Promise已经执行完毕,则抛出异常
        throw new IllegalStateException("complete already: " + this);
    }

    @Override
    public boolean trySuccess(V result) {
        // 设置成功结果,返回的布尔值表示成功或失败
        return setSuccess0(result);
    }

    @Override
    public Promise setFailure(Throwable cause) {
        // 设置失败结果,如果设置成功则返回当前Promise实例
        if (setFailure0(cause)) {
            return this;
        }
        // 设置失败说明了多次设置,Promise已经执行完毕,则抛出异常
        throw new IllegalStateException("complete already: " + this, cause);
    }

    @Override
    public boolean tryFailure(Throwable cause) {
        // 设置失败结果,返回的布尔值表示成功或失败
        return setFailure0(cause);
    }

    @SuppressWarnings("unchecked")
    @Override
    public V getNow() {
        // 非阻塞获取结果,如果result是CauseHolder类型、SUCCESS属性实例或者UNCANCELLABLE实行实例则返回null,否则返回转换类型后的result值
        // 对异常无感知,如果CauseHolder包裹了异常,此方法依然返回null
        Object result = this.result;
        if (result instanceof CauseHolder || result == SUCCESS || result == UNCANCELLABLE) {
            return null;
        }
        return (V) result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public V get() throws InterruptedException, ExecutionException {
        // 永久阻塞获取结果
        Object result = this.result;
        // 如果Promise未执行完毕则进行永久阻塞等待
        if (!isDone0(result)) {
            await();
            // 更新结果临时变量
            result = this.result;
        }
        // result为SUCCESS属性实例或者UNCANCELLABLE属性实例的时候直接返回null
        if (result == SUCCESS || result == UNCANCELLABLE) {
            return null;
        }
        // 如果result为CauseHolder类型,则获取其中持有的cause属性,也有可能为null
        Throwable cause = cause0(result);
        if (cause == null) {
            // 执行成功的前提下转换类型后的result值返回
            return (V) result;
        }
        // 取消的情况,抛出CancellationException
        if (cause instanceof CancellationException) {
            throw (CancellationException) cause;
        }
        // 剩余的情况一律封装为ExecutionException异常
        throw new ExecutionException(cause);
    }

    @SuppressWarnings("unchecked")
    @Override
    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        // 带超时时限的阻塞获取结果
        Object result = this.result;
        // 如果Promise未执行完毕则进行带超时时限的阻塞等待
        if (!isDone0(result)) {
            if (!await(timeout, unit)) {
                // 等待超时直接抛出TimeoutException
                throw new TimeoutException();
            }
            // 更新结果临时变量
            result = this.result;
        }
        // result为SUCCESS属性实例或者UNCANCELLABLE属性实例的时候直接返回null
        if (result == SUCCESS || result == UNCANCELLABLE) {
            return null;
        }
        // 如果result为CauseHolder类型,则获取其中持有的cause属性,也有可能为null
        Throwable cause = cause0(result);
        if (cause == null) {
            // 执行成功的前提下转换类型后的result值返回
            return (V) result;
        }
        // 取消的情况,抛出CancellationException
        if (cause instanceof CancellationException) {
            throw (CancellationException) cause;
        }
        // 剩余的情况一律封装为ExecutionException异常
        throw new ExecutionException(cause);
    }

    @Override
    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;
    }

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

    private boolean setFailure0(Throwable cause) {
        // 设置执行失败的结果,入参是Throwable类型,封装为CauseHolder,存放在CauseHolder实例的cause属性
        return setValue0(new CauseHolder(checkNotNull(cause, "cause")));
    }

    private boolean setValue0(Object objResult) {
        // CAS更新result为入参objResult,result的期望值必须为null或者UNCANCELLABLE才能更新成功
        if (RESULT_UPDATER.compareAndSet(this, null, objResult) || RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
            // 判断是否需要进行等待线程的通知
            if (checkNotifyWaiters()) {
                // 通知监听器进行回调
                notifyListeners();
            }
            return true;
        }
        return false;
    }
    
    // 判断是否需要进行等待线程的通知 - 其实是判断是否需要通知监听器回调
    private synchronized boolean checkNotifyWaiters() {
        // 如果等待线程数量大于0则调用Object#notifyAll()唤醒所有等待线程
        if (waiters > 0) {
            notifyAll();
        }
        // 如果listeners不为空(也就是存在监听器)的时候才返回true
        return listeners != null;
    }
    // ... 省略其他代码 ...
}    

Promise的基本使用

要使用NettyPromise模块,并不需要引入Netty的所有依赖,这里只需要引入netty-common

io.netty
    netty-common
    4.1.44.Final

EventExecutor选取方面,Netty已经准备了一个GlobalEventExecutor用于全局事件处理,这里可以直接选用(当然也可以自行实现EventExecutor或者用EventExecutor的其他实现类):

EventExecutor executor = GlobalEventExecutor.INSTANCE;
Promise promise = new DefaultPromise(executor);

这里设计一个场景:异步下载一个链接的资源到磁盘上,下载完成之后需要异步通知下载完的磁盘文件路径,得到通知之后打印下载结果到控制台中。

public class PromiseMain {

    public static void main(String[] args) throws Exception {
        String url = "http://xxx.yyy.zzz";
        EventExecutor executor = GlobalEventExecutor.INSTANCE;
        Promise promise = new DefaultPromise(executor);
        promise.addListener(new DownloadResultListener());
        Thread thread = new Thread(() -> {
            try {
                System.out.println("开始下载资源,url:" + url);
                long start = System.currentTimeMillis();
                // 模拟下载耗时
                Thread.sleep(2000);
                String location = "C:\\xxx\\yyy\\z.md";
                long cost = System.currentTimeMillis() - start;
                System.out.println(String.format("下载资源成功,url:%s,保存到:%s,耗时:%d ms", url, location, cost));
                DownloadResult result = new DownloadResult();
                result.setUrl(url);
                result.setFileDiskLocation(location);
                result.setCost(cost);
                // 通知结果
                promise.setSuccess(result);
            } catch (Exception ignore) {

            }
        }, "Download-Thread");
        thread.start();
        Thread.sleep(Long.MAX_VALUE);
    }

    @Data
    private static class DownloadResult {

        private String url;

        private String fileDiskLocation;

        private long cost;
    }

    private static class DownloadResultListener implements GenericFutureListener> {

        @Override
        public void operationComplete(Future future) throws Exception {
            if (future.isSuccess()) {
                DownloadResult downloadResult = future.getNow();
                System.out.println(String.format("下载完成通知,url:%s,文件磁盘路径:%s,耗时:%d ms", downloadResult.getUrl(),
                        downloadResult.getFileDiskLocation(), downloadResult.getCost()));
            }
        }
    }
}

执行后控制台输出:

开始下载资源,url:http://xxx.yyy.zzz
下载资源成功,url:http://xxx.yyy.zzz,保存到:C:\xxx\yyy\z.md,耗时:2000 ms
下载完成通知,url:http://xxx.yyy.zzz,文件磁盘路径:C:\xxx\yyy\z.md,耗时:2000 ms

Promise适用的场景很多,除了异步通知的场景也能用于同步调用,它在设计上比JUCFuture灵活很多,基于Future扩展出很多新的特性,有需要的可以单独引入此依赖直接使用。

Promise监听器栈深度的问题

有些时候,由于封装或者人为编码异常等原因,监听器的回调可能出现基于多个Promise形成的链(参考Issue-5302,a promise listener chain),这样子有可能出现递归调用深度过大而导致栈溢出,因此需要设置一个阈值,限制递归调用的最大栈深度,这个深度阈值暂且称为栈深度保护阈值,默认值是8,可以通过系统参数io.netty.defaultPromise.maxListenerStackDepth覆盖设置。这里贴出前面提到过的代码块:

private void notifyListeners() {
    EventExecutor executor = executor();
    // 事件执行器必须是事件循环类型,也就是executor.inEventLoop()为true的时候才启用递归栈深度保护
    if (executor.inEventLoop()) {
        // 获取当前线程绑定的InternalThreadLocalMap实例,这里类似于ThreadLocal
        final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
        // 获取当前线程的监听器调用栈深度
        final int stackDepth = threadLocals.futureListenerStackDepth();
        // 监听器调用栈深度如果不超过阈值MAX_LISTENER_STACK_DEPTH
        if (stackDepth 

如果我们想模拟一个例子触发监听器调用栈深度保护,那么只需要想办法在同一个EventLoop类型的线程中递归调用notifyListeners()方法即可。

最典型的例子就是在上一个Promise监听器回调的方法里面触发下一个Promise的监听器的setSuccess()(简单理解就是套娃),画个图理解一下:

技术图片

测试代码:

public class PromiseListenerMain {

    private static final AtomicInteger COUNTER = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        EventExecutor executor = ImmediateEventExecutor.INSTANCE;
        // root
        Promise root = new DefaultPromise(executor);
        Promise p1 = new DefaultPromise(executor);
        Promise p2 = new DefaultPromise(executor);
        Promise p3 = new DefaultPromise(executor);
        Promise p4 = new DefaultPromise(executor);
        Promise p5 = new DefaultPromise(executor);
        Promise p6 = new DefaultPromise(executor);
        Promise p7 = new DefaultPromise(executor);
        Promise p8 = new DefaultPromise(executor);
        Promise p9 = new DefaultPromise(executor);
        Promise p10 = new DefaultPromise(executor);
        p1.addListener(new Listener(p2));
        p2.addListener(new Listener(p3));
        p3.addListener(new Listener(p4));
        p4.addListener(new Listener(p5));
        p5.addListener(new Listener(p6));
        p6.addListener(new Listener(p7));
        p7.addListener(new Listener(p8));
        p8.addListener(new Listener(p9));
        p9.addListener(new Listener(p10));
        root.addListener(new Listener(p1));
        root.setSuccess("success");
        Thread.sleep(Long.MAX_VALUE);
    }

    private static class Listener implements GenericFutureListener> {

        private final String name;
        private final Promise promise;

        public Listener(Promise promise) {
            this.name = "listener-" + COUNTER.getAndIncrement();
            this.promise = promise;
        }

        @Override
        public void operationComplete(Future future) throws Exception {
            System.out.println(String.format("监听器[%s]回调成功...", name));
            if (null != promise) {
                promise.setSuccess("success");
            }
        }
    }
}

因为有safeExecute()兜底执行,上面的所有Promise都会回调,这里可以采用IDEA的高级断点功能,在步入断点的地方添加额外的日志,输出如下:

MAX_LISTENER_STACK_DEPTH(notifyListenersNow)执行---
监听器[listener-9]回调成功...
MAX_LISTENER_STACK_DEPTH(notifyListenersNow)执行---
监听器[listener-0]回调成功...
MAX_LISTENER_STACK_DEPTH(notifyListenersNow)执行---
监听器[listener-1]回调成功...
MAX_LISTENER_STACK_DEPTH(notifyListenersNow)执行---
监听器[listener-2]回调成功...
MAX_LISTENER_STACK_DEPTH(notifyListenersNow)执行---
监听器[listener-3]回调成功...
MAX_LISTENER_STACK_DEPTH(notifyListenersNow)执行---
监听器[listener-4]回调成功...
MAX_LISTENER_STACK_DEPTH(notifyListenersNow)执行---
监听器[listener-5]回调成功...
MAX_LISTENER_STACK_DEPTH(notifyListenersNow)执行---
监听器[listener-6]回调成功...
safeExecute(notifyListenersNow)执行----------
监听器[listener-7]回调成功...
safeExecute(notifyListenersNow)执行----------
监听器[listener-8]回调成功...

技术图片

这里笔者有点疑惑,如果调用栈深度大于8,超出的部分会包装为Runnable实例提交到事件执行器执行,岂不是把递归栈溢出的隐患变成了内存溢出的隐患(因为异步任务也有可能积压,除非拒绝任务提交,那么具体要看EventExecutor的实现了)?

小结

Netty提供的Promise工具的源码和使用方式都分析完了,设计理念和代码都是十分值得借鉴,同时能够开箱即用,可以在日常编码中直接引入,减少重复造轮子的劳动和风险。

个人博客

  • Throwable‘s Blog

(本文完 e-a-20200123 c-3-d)

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

标签:compare   递归调用   个人   操作   特定   原因   并发包   rup   说明   

原文地址:https://www.cnblogs.com/throwable/p/12231878.html


评论


亲,登录后才可以留言!