Netty详解(二):异步回调Future介绍

Netty源码中大量使用异步回调机制,不管是connect还是write,甚至bind操作都是异步回调。Netty的I/O操作都是异步的,这归功于Netty两大接口Future和Promise

Future

  1. 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倒计时
    账户到账一个亿
    
  2. 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

  1. 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();
    }
    
  2. 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麻将
会计审查-结果:代理人账户到账一个亿
金主麻将输了一个亿,金主主动查看账户:代理人账户到账一个亿
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EzrealYi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值