JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

Netty - 异步与回调

wys521 2024-11-19 12:51:29 精选教程 23 ℃ 0 评论

开始之前

异步与回调,一个有趣的话题。我们总是对异步编程抱有很大的兴趣,因为正确的运用异步,可以使你的程序变快。但我们又想在异步完成时获得通知,怎么办?在java的concurrent包中提供了Future接口,可以获取异步调用的返回结果,但这个获取是同步的,显然破坏了异步的调用形式。那么本文将会阐述如何使用 回调机制 让程序真正的异步

回调

回调是一种双向调用:在类A的a()方法中调用了类B的b()方法,b()方法执行完之后调用A的callback来告知b()方法已经执行完毕,那么如何才能调用到callback()呢,或者说如何做到通知A呢,很显然b()方法执行时要持有A的引用,所以B的b方法应该是:b(A ref)。

类似下面的伪代码:

class A{
  void a(B ref){
    ref.b();
  };
  void callback();
}
class B{
  void b(A ref){
    ...
    ref.callback();
  }
  main(){
    new A().a(new B());
  }
}

上面这种是同步回调,即回调放在同一个线程内,但我们更关注文章开篇提到的异步回调。

异步回调

两大要素:

  1. 回调接口(Callback)
  2. 回调监听(CallbackListener)

被调用方返回一个Callback给调用方调用方在Callback上注册监听。被调用方在程序最后执行监听。这里有一个注意点:当调用方在放置监听的时候发现被调用方已经完成了自己代码,则调用方需要立即执行监听。

下面是作者简单实现的异步回调例子:

public interface Callback{
  public void addListener(CallbackListener listener);//注册监听
  public void notifyListener();//唤起监听
  public void setComplete(boolean b);//标记被调用方已完成
}

public interface CallbackListener{
  public void operationComplete(Callback callBack);
}

public class DefaultCallback implements Callback {
    private List<CallbackListener> ls = new ArrayList<>();
    private boolean completed = false;
    @Override
    public void addListener(CallbackListener listener) {
        if(completed){//如果已完成,则立即执行
            listener.operationComplete(this);
        }else{
            ls.add(listener);
        }
    }
    @Override
    public void notifyListener() {
        for(CallbackListener l : ls){
            l.operationComplete(this);
        }
    }
    @Override
    public void setComplete(boolean b) {
        this.completed = b;
    }
}

上面是基本组件,下面我们定义一个 被调用方的例子

public class A{
  public Callback invoke(){
  Callback callback = new DefaultCallback();
    //用线程实现异步
    new Thread(new Runnable(){
      public void run(){
        System.out.println("do something...");
        callback.setComplete(true);
        callback.notifyListener();
      }
    }).start();
    return callback;
  }
}

写一个测试程序

public class Test {
    public static void main(String[] args) {
        A a = new A();
        Callback callback = a.invoke();
        callback.addListener(new CallbackListener() {
            @Override
            public void operationComplete(Callback callBack) {
                System.out.println("do callback...");
            }
        });
    }
}

如果大家用这几段代码做了测试就能体会到,异步回调除了可以异步通知之外,还能保证代码在逻辑上的同步。

Netty中的实现

Netty中实现回调或者future通知的机制与上面的相似。

Netty中对Channel上IO操作都会立马返回并得到一个ChannelFuture引用,我们可以在ChannelFuture中注册监听 - ChannelFutureListener,这样我们就能在操作完成时获得通知。如下利用此机制实现在 成功连接 后的一些操作:

Channe channel = ...;
ChannelFuture future = 
channel.connect(new InetSocketAddress("localhost",8848));
future.addListener(new ChannelFutureListener() {
      @Override
      public void operationComplete(ChannelFuture future) throws Exception {
          if(future.isSucess()){
            System.out.println("do something...");
          }else{
            ...
          }
      }
 });

结束语

本文的重点在于中篇的异步回调,如果能明白了这个模式,也就明白了Netty中完全异步是怎么实现的。建议大家可以结合最后netty的例子调式下,这样才会有更深的理解。

下篇将会继续介绍 读 写事件在netty中是如何优雅处理的。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表