Netty 框架学习 —— EventLoop 和线程模型


EventLoop 接口

Netty 是基于 Java NIO 的,所以 Channel 也有其生命周期,处理一个链接在其生命周期内发生的事件是全部网络框架的基本功能。一般来讲,咱们使用一个线程来处理一个链接,该链接的生命周期的某一事件就绪,则会调用对应的事件处理逻辑java

在 Netty 中,一个 EventLoop 负责处理一个 Channel 的生命周期事件。在代码设计上,EventLoop 间接实现了 JUC 中的 ExecutorService 和 ScheduleExecutorService 两个接口,所以其具备了线程池的特性。一个 EventLoop 将由一个永远不会改变的 Thread 驱动,EventLoop 由一个 Selector 和 TaskQueue 组成,Selector 会选择 Channel 生命周期中某一事件,并由 EventLoop 所在的线程选择对应的 ChannelHandler 进行处理。除此以外,用户还能够手动提交任务给 EventLoop,以当即执行或调度执行网络


任务调度

有时候,你但愿在 Channel 中调度一个任务以当即执行、稍后执行或者周期性执行。然而,这些任务有可能会形成长时间的阻塞,若是写在 ChannelHandler 里面,则有可能会阻塞整个执行链。所以,咱们能够把这些任务提交给 EventLoop,EventLoop 会把这些任务放入 TaskQueue 中,等待建立线程去执行,这个过程是异步非阻塞的,不会影响到主执行链框架

Channel ch = ...;
ScheduleFuture<?> future = ch.eventLoop().schedule(
    // 建立一个 Runnable 以供调度稍后执行
	new Runnable() {
        @Override
        public void run() {
            // 要执行的代码
            System.out.println("60 second later");
        }
    }, 60, TimeUnit.SECONDS);

由此咱们知道,EventLoop 所在线程负责一个 Channel 的整个生命周期内的全部事件。有时候,咱们还会在别的线程去获取一个 Channel,并向该 Channel 对应的 EventLoop 提交任务。这种非对应 Channel 所提交过来的任务,EventLoop 会把它放入任务队列中,等待下次执行异步


EventLoop 的线程分配

服务于 Channel 的 EventLoop 包含在 EventLoopGroup 中,根据不一样的传输实现,EventLoop 的建立和分配方式也不一样ide

1. 异步传输

异步传输实现只使用了少许的 EventLoop,一个 EventLoop 可能会被多个 Channel 所共享,经过尽量少的线程来支撑大量的 Channel,而不是每一个 Channel 分配一个 Threadoop

须要注意的是,一个 EventLoop 被用于支撑多个 Channel,那么对于全部相关联的 Channel 来讲,ThreadLocal 是同样的,这使得它对于实现状态追踪等功能来讲是个糟糕的选择线程

2. 阻塞传输

每个 Channel 都将分配给一个 EventLoop,每一个 Channel 的 IO 事件都将只会被一个 Thread 处理设计

相关文章
相关标签/搜索