前言

Netty系列索引:

1.Netty入门(一):ByteBuf

2.Netty入门(二):Channel

IO相关:

1.Java基础(一):I/O多路复用模型及Linux中的应用

上文提到,早期基于线程的网络模型,处理高并发的能力非常差,随着请求数量的增多,必须不断新建线程,随之带来的问题就是服务器资源被占满、上下文切换成本过高以及IO阻塞导致的CPU浪费。

而Netty则使用了经典Reactor模型,并重新进行了封装,包括EventLoop、EventGroup等。

EventLoopGroup

EventLoopGroup是一个接口,继承自线程池EventExecutorGroup,并允许注册channel到自身所持有的EventLoop,同时支持按一定规则获取下一个EventLoop。

EventLoopGroup的具体实现有很多,下面以DefaultEventLoopGroup为例,简述一下我的理解

1.ScheduledExecutorService

JDK接口,一个延迟或定时任务的执行器,其实现类ScheduledThreadPoolExecutor主要是利用了延时队列及设置下次执行时间来实现的,这里不再赘述(可以单独开个专题0.0)

2.EventExecutorGroup

接口,Netty自定义的一个线程池,负责复用EventExecutor和执行任务

3.EventLoopGroup

核心接口,EventLoopGroup继承自EventExecutorGroup,代表他是一个线程池。同时他具备将channel注册到EventExecutorGroup的功能,代表他是一个能够真正处理Channel的特殊线程池

4.MultithreadEventExecutorGroup(AbstractEventExecutorGroup)

抽象类,实现自EventExecutorGroup接口,提供了一个简易线程池的实现,其只有一个抽象方法newChild(创建EventExecutor)供子类实现

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args)

4.1 nThreads

    private final EventExecutor[] children;

该线程池通过数组存储线程,入参nThreads指定数组大小,并循环调用newChild创建线程。当创建过程中有异常时,会自动调用已创建完成线程的shutdownGracefully方法,进行优雅关闭

        for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
} for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}

4.2 EventExecutorChooserFactory

EventExecutorChooserFactory是一个工厂接口,负责创建EventExecutorChooser

其默认实现DefaultEventExecutorChooserFactory会判断当前线程数是否2的n次幂,如果是则返回PowerOfTwoEventExecutorChooser,否则返回GenericEventExecutorChooser

4.3 EventExecutorChooser

    private final EventExecutorChooserFactory.EventExecutorChooser chooser;

EventExecutorChooser负责根据一定规则从线程池children数组中取得下一个线程

PowerOfTwoEventExecutorChooser:通过&运算,将超出executors.length的位置为0

        public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}

GenericEventExecutorChooser:通过求余运算,获取有效index

        public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}

可以看出当线程数是2的n次幂时,Netty通过与运算优化了效率

5.MultithreadEventLoopGroup

抽象类,继承自MultithreadEventExecutorGroup并实现了EventLoopGroup接口,代表此抽象类是一个可以注册并处理channel的线程池

值得关注的是next方法,他把返回值的类型,进一步限定为EventLoop

    public EventLoop next() {
return (EventLoop) super.next();
}

6.DefaultEventLoopGroup

MultithreadEventLoopGroup的一个默认实现

其核心就是实现了newChild方法返回一个EventLoop extends EventExecutor实例

    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new DefaultEventLoop(this, executor);
}

7.总结

说白了EventLoopGroup核心方法,register负责将channel与线程池中某一线程绑定,next负责返回下一个线程供调用方执行任务

EventLoop

EventLoop直译为事件循环,他的职责简单来说就是绑定一个唯一的线程,去执行或调度被分配的任务。

可见一个EventLoop实例可以为多个channel服务,而为了最大化利用资源,Netty使用池化技术将EventLoop放入EventLoopGroup中管理。

EventLoop的具体实现有很多,先看下DefaultEventLoop的类图,会发现他和DefaultEventLoopGroup的类图很像,都继承了EventLoopGroup接口,但其最大的不同是红框所示,他还继承了EventExecutor,下面主要讲一下多出来的这部分到底是干了什么

1.EventExecutor

接口,定义了一个事件执行器,主要方法如下

    /**
* 直接返回自身
*/
@Override
EventExecutor next(); /**
* 返回所属线程池
*/
EventExecutorGroup parent(); /**
* 判断当前线程是否是当前EventLoop绑定的线程
*/
boolean inEventLoop(); /**
* 判断传入线程是否是当前EventLoop绑定的线程
*/
boolean inEventLoop(Thread thread);

(还涉及一些Future异步编程的一些东西,太复杂了后续再填坑吧0.0)

2.AbstractScheduledEventExecutor (AbstractEventExecutor)

抽象类,简单定义了一个支持延迟(定时)任务的执行器

    //延时队列
PriorityQueue<ScheduledFutureTask<?>> scheduledTaskQueue;
//下一个任务id
long nextTaskId;

重要方法scheduled

    private <V> ScheduledFuture<V> schedule(final ScheduledFutureTask<V> task) {
if (inEventLoop()) {
//如果和执行器绑定的线程一致,直接放入延时队列中
scheduleFromEventLoop(task);
} else {
//获取任务最晚执行时间
final long deadlineNanos = task.deadlineNanos();
// task will add itself to scheduled task queue when run if not expired
if (beforeScheduledTaskSubmitted(deadlineNanos)) {
//放入线程池执行
execute(task);
} else {
//与execute类似,但不保证任务会在执行非延迟任务或执行程序关闭之前运行,默认实现只是委托给execute(Runnable)
lazyExecute(task);
// Second hook after scheduling to facilitate race-avoidance
if (afterScheduledTaskSubmitted(deadlineNanos)) {
execute(WAKEUP_TASK);
}
}
} return task;
}

3.SingleThreadEventExecutor

抽象类,定义了一个单线程顺序执行器

    private void execute(Runnable task, boolean immediate) {
boolean inEventLoop = inEventLoop();
//添加到任务队列
addTask(task);
if (!inEventLoop) {
//启动线程
startThread();
//如果线程池已经关闭,调用拒绝方法
if (isShutdown()) {
boolean reject = false;
try {
if (removeTask(task)) {
reject = true;
}
} catch (UnsupportedOperationException e) {
// The task queue does not support removal so the best thing we can do is to just move on and
// hope we will be able to pick-up the task before its completely terminated.
// In worst case we will log on termination.
}
if (reject) {
reject();
}
}
}
//唤醒线程
if (!addTaskWakesUp && immediate) {
wakeup(inEventLoop);
}
}

4.SingleThreadEventLoop

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop 

EventLoop的抽象基类,负责在单线程中执行所有被提交的任务,同时具有注册和处理channle的能力

5.DefaultEventLoop

单线程任务执行器的默认实现,主要就是其实现的run方法

    protected void run() {
//循环阻塞的获取任务,知道被通知关闭
for (;;) {
Runnable task = takeTask();
if (task != null) {
task.run();
updateLastExecutionTime();
} if (confirmShutdown()) {
break;
}
}
}

6.总结

通过以上分析,不难看出Netty首先定义了自己的线程池(EventExectorGroup)和执行器(EventExector),然后通过继承的方式定义了线程池(EventLoopGroup)和执行器(EventLoop),从而添加了处理(注册)channel的能力。

You gotta grab what you can when you can.
机不可失,时不我待。

Netty入门(三):EventLoop的更多相关文章

  1. Netty入门(三)之web服务器

    Netty入门(三)之web服务器 阅读前请参考 Netty入门(一)之webSocket聊天室 Netty入门(二)之PC聊天室 有了前两篇的使用基础,学习本文也很简单!只需要在前两文的基础上稍微改 ...

  2. Netty 系列(三)Netty 入门

    Netty 系列(三)Netty 入门 Netty 是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更多请参考:Netty Github 和 Netty中文 ...

  3. netty入门(一)

    1. netty入门(一) 1.1. 传统socket编程 在任何时候都可能有大量的线程处于休眠状态,只是等待输入或者输出数据就绪,这可能算是一种资源浪费. 需要为每个线程的调用栈都分配内存,其默认值 ...

  4. 【原创】NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战

    前言 本文将演示一个iOS客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo.服务端将分别用MINA2和Netty4进行实现,而通信时服务端你只需选其一就行了.同 ...

  5. Netty入门之客户端与服务端通信(二)

    Netty入门之客户端与服务端通信(二) 一.简介 在上一篇博文中笔者写了关于Netty入门级的Hello World程序.书接上回,本博文是关于客户端与服务端的通信,感觉也没什么好说的了,直接上代码 ...

  6. Netty入门之HelloWorld

    Netty系列入门之HelloWorld(一) 一. 简介 Netty is a NIO client server framework which enables quick and easy de ...

  7. Netty入门

    一.NIO Netty框架底层是对NIO的高度封装,所以想要更好的学习Netty之前,应先了解下什么是NIO - NIO是non-blocking的简称,在jdk1.4 里提供的新api,他的他的特性 ...

  8. 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

    本文原作者:“竹千代”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.前言 无论是即时通讯应用还是传统的信息系统,Http协议都是我们最常打交 ...

  9. Netty入门(一)之webSocket聊天室

    一:简介 Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能.高可靠性协议的服务器和客户端. 换句话说,Netty 是 ...

随机推荐

  1. 五、JavaSE语言基础之流程控制

    流程控制的简单概念 流程控制:指通过关键字控制代码的执行流程; 一.顺序结构:执行顺序从左到右从上到下; 顺序结构无关键字,一般而言大多数代码都是顺序结构; 二.选择结构:根据条件判断是否执行 选择结 ...

  2. 21、linux系统grup和bios加密

    21.1.grup加密(加密单用户模式): 1.使用加密算法对grup密码进行加密: 2.修改grup.conf配置文件: 21.2.bios加密(因为救援模式可以破解grup加密,所以使用bios加 ...

  3. POJ 1279 Art Gallery 半平面交 多边形的核

    题意:求多边形的核的面积 套模板即可 #include <iostream> #include <cstdio> #include <cmath> #define ...

  4. Kafka:Springboot整合Kafka消息队列

    本文主要分享下Spring Boot和Spring Kafka如何配置整合,实现发送和接收来自Spring Kafka的消息. 项目结构 pom依赖包 <?xml version="1 ...

  5. Android java层常见加密算法的hook自吐以及栈信息的打印

    杂谈:其实原理并没有很难,本质就是hook Android的框架层中的api将我们想要的key和iv(也可以没有,就打个比方),但是目前的话,很多厂家已经不在直接调用java层的这些加密算法的api了 ...

  6. jenkins报错: error: insufficient permission for adding an object to repository database .git/objects

    前言:这是在用jenkins去gitlab上面去拉下代码来编译,就报了这个错,在这里记录下,避免下次 报错:   17:08:17 error: insufficient permission for ...

  7. ESP32-性能监控笔记

    基于ESP-IDF4.1 1 #include <stdio.h> 2 #include <string.h> 3 #include <unistd.h> 4 #i ...

  8. Git submodule 拉取子模块

    $ git clone https://code.Xcode.com.client.git Cloning into 'vipkid-pc-client'... Username for 'https ...

  9. Helm Template初体验,方便管理多环境

    我最新最全的文章都在南瓜慢说 www.pkslow.com,文章更新也只在官网,欢迎大家来喝茶~~ 1 简介 Helm作为一个优秀的包管理器,这部分我们之前已经做了介绍,文章如下: 用Helm部署Ku ...

  10. 如何搭建一个简易的 Web Terminal(一)

    前言 在介绍本篇文章的时候,先说一下本篇文章的一些背景.笔者是基于公司的基础建设哆啦 A 梦(Doraemon)一些功能背景写的这篇文章,不了解.有兴趣的同学可以去 袋鼠云 的 github 下面了解 ...