一、前言

  在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型。

二、EventLoop和线程模型

  2.1. 线程模型

  线程池可通过缓存和复用已有线程来提高系统性能,基本的缓冲池模式可描述如下:

    · 从池中空闲链表中选取线程,然后将其分配赋予给已提交的任务。

    · 当线程完成工作时,该线程又返回至空闲链表,可再进行复用。

  该模式如下图所示。

  

  池化和复用线程是针对每个任务都需要创建和销毁线程的改进,但还是需要进行上下文切换,并且随着线程数量的增加,其负担也会增加。同时,在高并发下也会出现很多线程问题。

  2.2. EventLoop接口

  任何网络框架的基本功能都是运行任务来处理在连接声明周期中所发生的事件,相应的编程结构通常被称为事件循环。事件循环的基本思想如下代码所示,每个任务都是一个Runnable实例。  

while (!terminated) {
List<Runnable> readyEvents = blockUntilEventsReady();
for (Runnable ev: readyEvents) {
ev.run();
}
}

  Netty的EventLoop是使用concurrency和networking两个基本API的协作设计的一部分,Netty中的io.netty.util.concurrent 包基于JDK的java.util.concurrent包进行设计。另外,io.netty.channel包中的类也继承它们,以便与其事件相关联,具体继承关系如下图所示。

  

  在这个模型中,EventLoop由一个永不改变的线程驱动,任务(Runnable或Callable)可以直接提交给EventLoop的实现,以便立即执行或有计划地执行。根据配置和可用内核,可以创建多个EventLoops以优化资源使用,并且可以为单个EventLoop分配服务多个通道。

  事件和任务以FIFO的方式被执行,这通过保证以正确的顺序处理字节内容来消除数据损坏的可能性。

  1. Netty 4中的I/O和事件处理

  由I/O操作触发的事件流过具有一个或多个ChannelHandler的ChannelPipeline时,传播这些事件的方法调用可以由ChannelHandler拦截,并根据需要进行处理,根据事件的不同,需要进行不同的处理,但事件处理逻辑必须具有通用性和灵活性,以处理所有可能的用例,因此,在Netty 4中,所有的I/O操作和事件都由已分配给EventLoop的线程处理。

  2. Netty 3中的I/O处理

  以前版本中使用的线程模型仅保证入站(上游)事件将在所谓的I/O线程中执行,所有出站(下游)事件由调用线程处理,其需要在ChannelHandlers中仔细同步出站事件,因为不可能保证多个线程不会同时尝试访问出站事件。

  2.3 任务调度

  有时需要让一个任务稍后(延迟)或定期执行,一个常见的用例是向远程对等体发送心跳消息,以检查连接是否仍然存在。

  1. JDK调度API

  在Java 5之前,任务调度基于java.util.Timer构建,其使用后台线程,与标准线程具有相同的限制,随后,Java提供了ScheduledExecutorService接口,如下代码在60S后执行任务。  

ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
ScheduledFuture<?> future = executor.schedule(
new Runnable() {
@Override
public void run() {
System.out.println("60 seconds later");
}
}, 60, TimeUnit.SECONDS); executor.shutdown();

  2. 使用EventLoop调度任务

  ScheduledExecutorService实现有限制,如为管理池需要创建额外的线程,如果许多任务被调度,这可能会成为系统性能瓶颈。Netty通过使用Channel的EventLoop调度来解决这个问题,如下代码所示。  

Channel ch = ...
ScheduledFuture<?> future = ch.eventLoop().schedule(
new Runnable() {
@Override
public void run() {
System.out.println("60 seconds later");
}
}, 60, TimeUnit.SECONDS);

  60秒后,Runnable实例将由分配给该Channel的EventLoop执行。若想每隔60S执行任务,则需要做如下处理。  

Channel ch = ...
ScheduledFuture<?> future = ch.eventLoop().scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
System.out.println("Run every 60 seconds");
}
}, 60, 60, TimeUnit.Seconds);

  因为EventLoop继承ScheduledExecutorService,因此可以调用ScheduledExecutorService的所有方法。

  2.4 实现细节

  1. 线程管理

  Netty的线程模型的优越性能取决于确定当前正在执行的线程的身份,即是否为分配给当前Channel及其EventLoop的线程。如果调用的是EventLoop的线程,那么直接执行该代码块,否则,EventLoop调度一个任务以供稍后执行,并将其放入内部队列中,当处理下个事件时,会处理队列中的事件,这解释了任何线程为何可以直接与Channel交互,而不需要在ChannelHandler中同步。

  每个EventLoop都有自己的任务队列,与其他EventLoop独立,下图显示了EventLoop的执行逻辑。

  

  不要把长时间的任务放在执行队列中,因为它将阻止任何其他任务在同一个线程上执行。如果必须进行阻塞调用或执行长时间运行的任务,建议使用专用的EventExecutor。

  2. EventLoop/线程的分配

  为通道的I/O和事件提供服务的EventLoops包含在EventLoopGroup,EventLoops创建和分配的方式根据传输实现(异步和阻塞)而有所不同。

  · 异步传输。只使用少量的EventLoopGroup,在当前的模型中其在通道中共享。这允许通道由最小数量的线程提供服务,而不是为每个通道分配一个线程。下图展示了包含三个EventLoop(每个EventLoop由一个线程驱动)的EventLoopGroup,EventLoopGroup创建时会直接分配EventLoops(及其线程),以确保它们在需要时可用,EventLoopGroup负责将EventLoop分配给每个新创建的通道,当前的实现是使用循环方法实现均衡分配,相同的EventLoop可被分配给多个通道

  

  一旦一个Channel被分配了一个EventLoop,它将在其生命周期中一直使用这个EventLoop(和相关联的线程)。同时请注意EventLoop的分配对ThreadLocal影响,因为一个EventLoop通常驱动多个通道,多个通道的ThreadLocal也相同。

  · 阻塞传输。OIO的实现与异步传输的实现大不相同,其如下图所示。

  

  每个通道将会分配一个EventLoop(以及相关线程),Channel的IO事件将由独立的线程处理。

三、总结

  本篇博文讲解了EventLoop及其线程模型,以及其与通道之间的关系,EventLoopGroup可对应多个EventLoop,一个EventLoop对应一个线程,一个EventLoop可对应多个通道。也谢谢各位园友的观看~

【Netty】EventLoop和线程模型的更多相关文章

  1. Netty学习摘记 —— 再谈EventLoop 和线程模型

    本文参考 本篇文章是对<Netty In Action>一书第七章"EventLoop和线程模型"的学习摘记,主要内容为线程模型的概述.事件循环的概念和实现.任务调度和 ...

  2. Netty实战七之EventLoop和线程模型

    简单地说,线程模型指定了操作系统.编程语言.框架或者应用程序的上下文中的线程管理的关键方面.Netty的线程模型强大但又易用,并且和Netty的一贯宗旨一样,旨在简化你的应用程序代码,同时最大限度地提 ...

  3. Netty中的EventLoop和线程模型

    一.前言 在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型. 二.EventLoop和线程模型 2.1. 线程模型 线 ...

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

    EventLoop 接口 Netty 是基于 Java NIO 的,因此 Channel 也有其生命周期,处理一个连接在其生命周期内发生的事件是所有网络框架的基本功能.通常来说,我们使用一个线程来处理 ...

  5. Netty(二) 从线程模型的角度看 Netty 为什么是高性能的?

    前言 在之前的 SpringBoot 整合长连接心跳机制 一文中认识了 Netty. 但其实只是能用,为什么要用 Netty?它有哪些优势?这些其实都不清楚. 本文就来从历史源头说道说道. 传统 IO ...

  6. 3 - EventLoop和线程模型-事件循环

    a). EventLoopGroup为每个新创建的channel分配一个EventLoop,多个channel对应一个EventLoop. b). 一个EventLoop由一个不变的thread驱动, ...

  7. Netty源码死磕一(netty线程模型及EventLoop机制)

    引言 好久没有写博客了,近期准备把Netty源码啃一遍.在这之前本想直接看源码,但是看到后面发现其实效率不高, 有些概念还是有必要回头再细啃的,特别是其线程模型以及EventLoop的概念. 当然在开 ...

  8. Reactor三种线程模型与Netty线程模型

    文中所讲基本都是以非阻塞IO.异步IO为基础.对于阻塞式IO,下面的编程模型几乎都不适用 Reactor三种线程模型 单线程模型 单个线程以非阻塞IO或事件IO处理所有IO事件,包括连接.读.写.异常 ...

  9. 从线程模型的角度看Netty的高性能

    转载:Netty(二) 从线程模型的角度看 Netty 为什么是高性能的? 传统 IO 在 Netty 以及 NIO 出现之前,我们写 IO 应用其实用的都是用 java.io.* 下所提供的包. 比 ...

随机推荐

  1. WPF 杂谈——开篇简言。

    这俩年多来笔者一直在从事关于WPF的开发.虽然不能说是专家级别的.但是对于WPF的应用还是有一定的了解.论他的灵活性决对不在WinForm之下.WPF的出现更是引发一段热议.他的何去何从更是让很多人感 ...

  2. Java设计模式面试题 01 - 六大原则

    Java设计模式面试题 01 - 六大原则 1. 单一职责原则 Single Responsibility Principle SRP原则 分清职责,接口一定要做到单一职责,方法也要做到,类尽量做到 ...

  3. 关于for()循环使用过程中遇到的问题(俄罗斯方块游戏中遇到的问题)

    for循环的定义: for(参数1:参数2:参数3),参数1通常是初始化参数的,参数2是判断,参数3是对参数的操作.这三个参数都不是必须的. 这里想说的是,参数1的使用:比如下列语 int nLine ...

  4. jmeter 使用jmeter 录制web脚本

    1.打开jmeter.鼠标右击工作台.添加HTTP代理服务器 2.设置端口号.目标控制器.分组 3.添加查看结果树 4.点击启动.确定完成 5.打开浏览器直接进行操作.就可以看到所录制的脚本信息

  5. alert 和 console.log的区别

    出走半月,一直以为 console.log 和 alert 的用法是一样的,只是表现的形式不同,alert 是以弹框的形式出现,console.log 是在后台打印输出. 但是今天在写东西的时候,发现 ...

  6. java集合基础

    集合概念与作用 1现实生活中把很多事物凑在一起就是集合.java中的集合类:是一种工具,就像是容器,存储任意数量的有共同属性的对象. 2在类的内部,对数据进行组织: 简单而快速的搜索大数量的条目 有的 ...

  7. Jquery对select下拉框的操作

    一.jQuery获取Select选择的Text和Value:语法解释: $("#select_id").change(function(){//code...});   //为Se ...

  8. js:通过正则匹配获取页面的url中的参数

    简介:获取页面参数 原生js: //通过正则匹配获取当前页面的url中的参数 function getUrlParam(name){ var reg = new RegExp("(^|&am ...

  9. C 语言实现字符串替换

    void replaceFirst(char *str1,char *str2,char *str3) { ]; char *p; strcpy(str4,str1); if((p=strstr(st ...

  10. 什么是PROFINET IO系统的实时性

    实时系统是指系统能及时响应外部事件的请求,在规定的时间内完成对该事件的处理,并控制所有实时任务协调一致的运行. PROFINET IO系统的实时性就是指当有一个外部事件发生时,从输入信号到传输.到控制 ...