netty系列之:EventLoop,EventLoopGroup和netty的默认实现
简介
在netty中不管是服务器端的ServerBootstrap还是客户端的Bootstrap,在创建的时候都需要在group方法中传入一个EventLoopGroup参数,用来处理所有的ServerChannel和Channel中所有的IO操作和event。
可能有的小伙伴还稍微看了一下netty的源码,可能会发现还有一个和EventLoopGroup非常类似的类叫做EventLoop。那么EventLoopGroup和EventLoop有什么关系呢?他们的底层和channel的交互关系是怎么样的呢?一起来看看吧。
EventLoopGroup和EventLoop
EventLoopGroup继承自EventExecutorGroup:
public interface EventLoopGroup extends EventExecutorGroup
在前面的文章中我们讲过,EventExecutorGroup中有一个next方法可以返回对应的EventExecutor,这个方法在EventLoopGroup中进行了重写:
    EventLoop next();
next方法返回的不再是一个EventExecutor,而是一个EventLoop。
事实上,EventLoop和EventLoopGroup的关系与EventExecutor和EventExecutorGroup的关系有些类似,EventLoop也是继承自EventLoopGroup,EventLoopGroup是EventLoop的集合。
public interface EventLoop extends OrderedEventExecutor, EventLoopGroup
在EventLoopGroup中,除了重写的next方法之外,还添加了channel的注册方法register,用于将channel和注册到EventLoop中,从而实现channel和EventLoop的绑定。
ChannelFuture register(Channel channel);
在EventLoop中,自多添加了一个parent方法,用来表示EventLoop和EventLoopGroup的关联关系:
EventLoopGroup parent();
EventLoopGroup在netty中的默认实现
EventLoopGroup在netty中的默认实现叫做DefaultEventLoopGroup,先来看一下它的继承关系:

如果看了之前我讲解的关于EventExecutorGroup的朋友可以看出来,DefaultEventLoopGroup和DefaultEventExecutorGroup的继承关系是很类似的,DefaultEventLoopGroup继承自MultithreadEventLoopGroup,而MultithreadEventLoopGroup又继承自MultithreadEventExecutorGroup并且实现了EventLoopGroup接口:
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup
MultithreadEventLoopGroup是用多线程来处理Event Loop。
在MultithreadEventLoopGroup中定义了一个DEFAULT_EVENT_LOOP_THREADS来存储默认的处理Event Loop线程的个数:
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
                "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
对于EventLoopGroup中新加的几个register方法,MultithreadEventLoopGroup都是调用对应的next方法来实现的:
public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }
这里的next()方法的实现实际上调用的是父类的next方法,也就是MultithreadEventExecutorGroup中的next方法,来选择Group管理的一个EventLoop:
public EventLoop next() {
        return (EventLoop) super.next();
    }
对于DefaultEventLoopGroup来说,它继承自MultithreadEventLoopGroup,实现了一个newChild方法,用来将传入的executor封装成为EventLoop:
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        return new DefaultEventLoop(this, executor);
    }
EventLoop在netty中的默认实现
EventLoop在netty中的默认实现叫做DefaultEventLoop,先来看下它的继承关系:

DefaultEventLoop继承自SingleThreadEventLoop,而SingleThreadEventLoop又继承自SingleThreadEventExecutor并且实现了EventLoop接口。
先来看下SingleThreadEventLoop的实现:
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop
SingleThreadEventLoop使用单一线程来执行提交的任务。它和SingleThreadEventExecutor相比有什么变化呢?
首先 提供了一个tailTasks用来存储pending的tasks:
private final Queue<Runnable> tailTasks;
这个tailTasks会被用在任务个数的判断和操作上:
    final boolean removeAfterEventLoopIterationTask(Runnable task) {
        return tailTasks.remove(ObjectUtil.checkNotNull(task, "task"));
    }
    protected boolean hasTasks() {
        return super.hasTasks() || !tailTasks.isEmpty();
    }
    public int pendingTasks() {
        return super.pendingTasks() + tailTasks.size();
    }
SingleThreadEventLoop中对register方法的实现最终调用的是注册的channel中unsafe的register方法:
channel.unsafe().register(this, promise);
再来看一下DefaultEventLoop,DefaultEventLoop继承自SingleThreadEventLoop:
public class DefaultEventLoop extends SingleThreadEventLoop
除了构造函数之外,DefaultEventLoop实现了一个run方法,用来具体任务的执行逻辑:
    protected void run() {
        for (;;) {
            Runnable task = takeTask();
            if (task != null) {
                task.run();
                updateLastExecutionTime();
            }
            if (confirmShutdown()) {
                break;
            }
        }
    }
如果对比可以发现,DefaultEventLoop和DefaultEventExecutor中run方法的实现是一样的。
总结
本文介绍了netty中EventLoop和EventLoopGroup的默认实现:DefaultEventLoop和DefaultEventLoopGroup,但是不知道小伙伴们有没有发现,即使在最简单的netty应用中也很少看到这两个默认的EventLoop。最常用的反而是NioEventLoopGroup和NioEventLoop,这是因为DefaultEventLoop和DefaultEventLoopGroup只是使用了多线程技术,一个线程代表一个EventLoop,在EventLoop过多的情况下可能会造成线程和性能的浪费,所以在NioEventLoopGroup和NioEventLoop使用了NIO技术,通过使用channel、selector等NIO技术提升了EventLoop的效率。关于NioEventLoopGroup和NioEventLoop的详细介绍,我们会在后一章中详细讲解,敬请期待。
本文已收录于 http://www.flydean.com/05-1-netty-eventloop-eventloopgroup/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
netty系列之:EventLoop,EventLoopGroup和netty的默认实现的更多相关文章
- netty系列之:Bootstrap,ServerBootstrap和netty中的实现
		
目录 简介 Bootstrap和ServerBootstrap的联系 AbstractBootstrap Bootstrap和ServerBootstrap 总结 简介 虽然netty很强大,但是使用 ...
 - netty系列之:EventExecutor,EventExecutorGroup和netty中的实现
		
目录 简介 EventExecutorGroup EventExecutor EventExecutorGroup在netty中的基本实现 EventExecutor在netty中的基本实现 总结 简 ...
 - netty系列之:channel,ServerChannel和netty中的实现
		
目录 简介 channel和ServerChannel netty中channel的实现 AbstractChannel和AbstractServerChannel LocalChannel和Loca ...
 - Netty系列之Netty线程模型
		
Reference: http://www.infoq.com/cn/articles/netty-threading-model 1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 ...
 - netty系列之:netty初探
		
目录 简介 netty介绍 netty的第一个服务器 netty的第一个客户端 运行服务器和客户端 总结 简介 我们常用浏览器来访问web页面得到相关的信息,通常来说使用的都是HTTP或者HTTPS协 ...
 - netty系列之:中国加油
		
目录 简介 场景规划 启动Server 启动客户端 消息处理 消息处理中的陷阱 总结 简介 之前的系列文章中我们学到了netty的基本结构和工作原理,各位小伙伴一定按捺不住心中的喜悦,想要开始手写代码 ...
 - Netty 系列一(核心组件和实例).
		
一.概念 早期的 Java API 只支持由本地系统套接字库提供所谓的阻塞函数来支持网络编程.由于是阻塞 I/O ,要管理多个并发客户端,需要为每个新的客户端Socket 创建一个 Thread .这 ...
 - Netty 系列(三)Netty 入门
		
Netty 系列(三)Netty 入门 Netty 是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更多请参考:Netty Github 和 Netty中文 ...
 - 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?
		
[读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...
 
随机推荐
- linux用户密码过期导致命令执行失败
			
背景介绍: 使用zabbix调用系统命令,检查时间同步,发现一直在报错,root 用户执行无异常,问题还是出现zabbix用户上面. [zabbix@test-10-12 ~]$ sudo ntpda ...
 - SpringBoot+Minio搭建不再爆肝秃头的分布式文件服务器
			
前言 1).有人一定会问,为什么不用FastDFS?众所周知,FastDFS的原生安装非常复杂,有过安装经验的人大体都明白,虽然可以利用别人做好的docker直接安装,但真正使用过程中也可能出现许多莫 ...
 - Python初学笔记列表&元组&字典
			
一.从键盘获取 1 print("请输入") 2 username = input("姓名:") 3 age = input("年龄:") ...
 - APschedule定时任务
			
APScheduler是Python的一个定时任务框架,可以很方便的满足用户定时执行或者周期执行任务的需求, 它提供了基于日期date.固定时间间隔interval .以及类似于Linux上的定时任务 ...
 - Redis学习笔记(三)redis 的键管理
			
Redis 的键管理 一.Redis 数据库管理 Redis 是一个键值对(key-value pair)的数据库服务器,其数据保存在 src/server.h/redisDb 中(网上很多帖子说在 ...
 - 计算机电子书 2017 BiliDrive 备份
			
下载方式 根据你的操作系统下载不同的 BiliDrive 二进制. 执行: bilidrive download <link> 链接 文档 链接 斯坦福 cs224d 深度学习与自然语言处 ...
 - ApacheCN Java 译文集 20211012 更新
			
Effective Java 中文第三版 1. 考虑使用静态工厂方法替代构造方法 2. 当构造方法参数过多时使用 builder 模式 3. 使用私有构造方法或枚类实现 Singleton 属性 4. ...
 - 营销MM让我讲MySQL日志顺序读写及数据文件随机读写原理
			
摘要:你知道吗,MySQL在实际工作时候的两种数据读写机制? 本文分享自华为云社区<MySQL日志顺序读写及数据文件随机读写原理>,作者:JavaEdge . MySQL在实际工作时候的两 ...
 - java中使用反射获取pojo(实体)类的所有字段值
			
出处:https://developer.aliyun.com/article/239346 说起反射,不得不说它实在是太强大了,通过反射就可以轻轻松松拿到各种东东,如果你想在项目中解除对某个类的依赖 ...
 - 模仿系统的UIImageView
			
整体思路: 我们想要模仿系统的UIImageView,我们必须得要知道系统的UIView怎么用. 系统的用法是创建一个UIImageView对象,设置frame,给它传递一个UIIma ...