提要
线程模子概述
一个基于线程池的模式可以描写为:
池和重用改进了每个任务建设和销毁一个线程的开销,但这并没有消除线程上下文切换的开销,跟着线程的增加这种开销会快速显现,而且在负载较重的环境下变得严峻。
EventLoop 接口
执行一个任务用于处理惩罚一个毗连生命周期期间碰着的事件,这是任何一个网络框架的根基成果。相应的网络布局常常会引用一个事件轮回( event loop ),Netty回收 io.netty.channel.EventLoop 接口。
一个事件轮回的根基思想通过的例子来展示:
Netty的EventLoop是一个协作设计的一部门,该协作设计利用了两个根基APIs:并发 和 网络。第一个是,io.netty.util.concurrent包,该包依赖于JDK java.util.concurrent包,用于提供线程执行器。第二个的类在包io.netty.channel中,扩展该类为了与Channel事件对接。
归纳综合的说,EventLoop用于遍历依次执行所有可运行的事件和任务,那么事件和任务在哪执行了?这里就需要通过EventExecutor来为事件/任务提供的执行器。而EventExecutor底层则是依赖于JDK 的java.util.concurrent包中的Executor来实现执行器的。
一个EventLoop由一个永远不会改变的线程所驱动,而且任务( Rannable 或 Callable )能被直接提交给EventLoop实现当即或按时的执行。
Event/Task 执行的顺序:事件和任务按照FIFO( 先进先出 )的顺序被执行。这消除了数据损坏的大概性,因此担保了以正确的顺序处理惩罚字节内容。
依赖系统设置和有效焦点,可以建设多个EventLoops以使资源利用最优化,而且一个EventLoop大概被分派与处事多个Channels。
Netty4 中的I/O和事件处理惩罚
I/O操纵触发一个事件,该事件流经含有一个或多个ChannelHandlers实例的ChannelPipeline。流传这些事件的要领挪用能被ChannelHandler拦截,并按照需要处理惩罚事件。
一个事件的本质凡是抉择了它该被如那里理惩罚;它大概转换数据从网络栈到你的应用中,或执行相反操纵,图纸加密,或执行完全差异的操纵。但事件处理惩罚逻辑必需是通用的而且足够机动去处理惩罚所有环境。因此,在Netty4中所有I/O操纵和事件处理惩罚都在EventLoop地址的线程上执行。
这与Netty3是差异的。
Netty3 中的I/O操纵
在早前的版本的线程模式中,仅担保所有的入站事件会在I/O线程(相当于Netty 4 中的EventLoop)上执行。所有的出站事件将通过挪用线程来处理惩罚,该线程大概是I/O线程也大概是其他线程。起初这看似是一个好主意,可是很快这被认为是会有问题的,因为我们需要小心出站事件在ChannelHandler的同步性 ( 好比,你再差异的线程中同时挪用了同一个Channel的Channel.write()要领。因此出站的ChannelHandler可以被多个线程同时要领,这就存在了同步性问题 )。总而言之,多个线程不会实验同时会见一个出站事件,这是无法担保的。这是大概产生的,好比,你再差异的线程中同时挪用了同一个Channel的Channel.write()要领,以此触发了沟通的下游事件。
另一个消极的副浸染产生在,当一个入站事件作为一个出站事件的功效被触发。当Channel.write()导致了一个异常,你需要发生并触发一个exceptionCaught事件。但在Netty3模式中,因为exceptionCaught是一个入站事件,你将在挪用线程上去挂起执行代码的线程(即,挂起执行Channel.write的线程),然后到I/O线程上执行该异常事件,这发生了特另外线程上下文切换。
Netty4所回收的线程模式办理了该问题,通过处理惩罚所有的工作在一个给定EventLoop上的同一个线程。这提供了一个简朴的执行架构并消除了ChannelHandler的同步须要性( 除了可在多个Channels共享的ChannelHandler )。
按时任务
偶然你需要延迟处理惩罚一个任务或按时周期性处理惩罚一个任务。好比,你大概想要注册一个事件用于清除一个客户端毗连,当该客户端已经毗连5分钟后。一个常见的利用场景是发送一个心跳包动静到远端去查抄毗连是否还在世。假如没后收到回覆,软件开发,你就知道你可以或许封锁这个Channel。