您的位置:首页 > 运维架构

Netty inEventLoop方法?异步回调?Promise?

2020-04-07 12:11 1476 查看

文章目录

inEventLoop

一直对这个方法不是很理解,众所周知是判断当前线程是不是在当前的EventLoop中对应的那个线程?
一个channel对应一个且只对应一个EventLoop,一个Channel对应一个且只对应一个Pipeline,Pipline中包含handler(也是context),当前的Handler被Channel调用,那什么时候执行这段代码的线程不是channel对应的那个EventLoop中的线程?

EventExecutor中最关键的是inEventLoop方法,用于判断一个线程是否是EventExecutor内部那个线程,EventExecutor和EventLoop都是单线程实现。inEventLoop的主要使用场景是,当IO变化时,通过channel关联的pipeline会触发对应的事件,这些事件对应的执行pipeline中的处理链中handler的回调方法,

每个handler添加到pipeline都可以指定自己的EventLoop,如果没指定,默认使用要添加的pipeline关联的channel注册到的EventLoopGroup中的某个EventLoop。
所以channel通过pipeline调用handler时,如果handler没有单独指定EventLoop,那inEventLoop就会返回true,他俩由同一个线程处理,直接调用handler。如果handler单独指定了EventLoop,inEventLoop就会返回false,channel调用handler时就把要调用的方法封装到Runnable里,然后添加到handler指定的EventLoop的任务队列里,稍后会由对应的EventLoop中的线程执行。

来自:https://www.jianshu.com/p/d39ff4c98c5f

至于代码分析就不贴代码了,没有什么特别的,关键是情况的分析。

自己画了个图方便理解,当然肯定还有不对的地方,理解的不是很好,有问题希望提出共同进步!

所以会有下面两种情况

在handler中:
executor.inEventLoop()?
当前executor是channel对应的那个eventLoop,而inEventLoop中的currentThread是handler自定义的eventLoop,是不相等的。所以是false,false的时候将handler中的回调封装成task放到自己对应的eventLoop的任务队列中

这就是异步

当前的channel相当于是主线程,主线程想要回调,发现当前的handler有自己的处理线程,那么就把回调方法封装成task给他自己的Executor中的queue中,他自己去执行吧,我该干嘛干嘛去了。

为什么返回Promise

阿西,实在不想贴代码
平常用户代码习惯这么写:

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ChannelFuture future = ctx.writeAndFlush("test data");
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()){
System.out.println("写出成功");
}else{
System.out.println("写出失败");
}
}
});
}

为什么writeAndFlush返回future,下面通过future调用addListener?
在writeAndFlush方法中返回了promise,也就是future

在addListener方法中有一个isDone方法

然后isDone0

判断result状态,这个result状态就是DefaultPromise中的,在writeAndFlush中flush也能修改这个状态,所以是在writeAndFlush和addListener中相同的。

Promise继承自Future,Future中有isSuccess方法

所以在operationComplete方法中能够执行future.isSuccess(),即这个

promise(也就是futrure)是writeAndFlush和addListener的一个桥梁,分享着当前是否能够回调的状态(是不是写完了)

这理解其实和JDK JUC中的Future是一个意思了:
promise(也就是futrure)中的result也是一个状态值,如果writeAndFlush完成了,设置值success,并且去

主动
唤醒,或者在addListener中
主动
唤醒。
区别就是Future中是通过get方法
被动
唤醒的,所以时机可能不是那么的准确。

另外jdk中的futrue方法是通过get阻塞进行的,runnable通过run生产数据,Future通过get获取数据,FuturetTask被两者共享,继承自他们两个,拥有了run和get这两个功能,在

自导自演
,run中执行callable的call方法,执行完成设置可执行标志,没有完成则标志还是未完成的,get方法一直阻塞,可是如果已经生产好了,而没有get呢?所以在Netty中通过listener这种方法更加精准的添加了监听,能够第一时间回调。

拾遗

什么是异步?
是否要等待一个操作的完成?

什么是阻塞?
是否要等待一个数据准备好?

当然在Netty中还有一个比较有意思的:

WriteAndFlush和addListener方法,如果是异步的,在writeAndFlush之前,完成了AddListener,那么在WriteAndFlush执行完write有异常回调,或者,执行完flush回调operationComplete的时候,设置为了Success,是可以放心回调的。
可是如果是两个方法如果是同步执行,当然异步执行也可能,writeAndFlush执行完了,result设置为了Success,但是AddListener还没有添加,那要怎么回调?operationComplete还没有准备好呢。通过看源码能够知道notifyListenersNow的时候,先判断listeners(其实就是listener)是不是没有,没有直接return了,那不就意味着这次wirteAnfFlush事件没有回调了? 其实在AddListener方法中,会进行一次判断,判断当前的result是不是Success,是的话就会进行一次回调。
代码分析略。

还有ByteBuf的缓存和命中也应该细细体会。

声明:
笔者本身还是一个小白,只看到了冰山一角,不一定完全正确,如果文中存在严重的错误,还请不吝指出,不仅利于自己的修正,同时也减少他人产生对于知识的误解。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
Leesin Dong 博客专家 发布了554 篇原创文章 · 获赞 4005 · 访问量 283万+ 他的留言板 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: