龙空技术网

Netty 线程模型

java任我行 481

前言:

而今你们对“netty业务线程池设置”可能比较珍视,姐妹们都想要分析一些“netty业务线程池设置”的相关资讯。那么小编也在网摘上搜集了一些对于“netty业务线程池设置””的相关文章,希望各位老铁们能喜欢,姐妹们一起来学习一下吧!

1. 前言

前面几节分别讲解了 Reactor 的三种线程模型,都知道主从 Reactor 多线程模型的性能非常的好,那么 Netty 是否就是使用主从 Reactor 多线程模型呢?其实 Netty 线程模型是基于主从 Reactor 多线程模型做了一定的改造,Netty 的线程模型要比 Reactor 主从多线程模型还要复杂。本节主要是通过图解的方式逐步分析 Netty 线程模型的原理。

2. Netty 模型介绍2.1 模型介绍

Netty 模型架构说明:

Netty 抽象出两个线程池,分别是 BossGroup 和 WorkerGroup,BossGroup 专门负责接受客户端的连接,Worker 请求处理;BossGroup 和 WorkerGroup 类型默认使用的是 NioEventLoopGroup;NioEventLoopGroup 是一个定时任务线程池,NioEventLoop 是真正工作的线程;每个 BossGroup 的 NioEventLoop 分别循环执行三个步骤

4.1 每个 NioEventLoop 都有一个 Selector,并且不断轮询 accept 事件;

4.2 处理 accept 事件,与客户端建立连接,生成 NioSocketChannel,并且将其注册到某个 WorkerGroup 下的 NioEventLoop 上的 Selector 上;

4.3 处理任务队列中的任务,即 runAllTasks。每个 WorkerGroup 的 NioEventLoop 分别循环执行三个步骤

5.1 轮询 read 和 write 事件;

5.2 处理 I/O 事件,即 read,write 事件,并在其对应的 NioSocketChannel 处理;

5.3 处理任务队列的任务,即 runAllTasks。2.2 核心概念理解

Tips: 额外知识点补充,这里提前剧透一下 Channel、ChannelPipeline、ChannelHanlder 之间的关系

每个客户端连接进来的时候,服务端都会建立一个 Channel;为每个 Channel 绑定一个 NioEventLoop 线程,该线程主要负责处理该 Channel 的业务,一个 Channel 对应一个 NioEventLoop,但是一个 NioEventLoop 可以同时服务多个 Channel;为每个 Channel 绑定一个 ChannelPipeline,它是一个业务管道,专门负责管理业务链,也就是 ChannelHandler;WorkerGroup 的核心方法是 runAllTasks (),它主要是触发 NioEventLoop 去处理对应的 Channel 里面的 ChannelPipeline 里面的 ChannelHandler 里面的业务逻辑。3. Netty 模型配置3.1 单线程配置

在 ServerBootstrap 调用方法 group 的时候,传递的参数是同一个线程组,且在构造线程组的时候,构造参数为 1。

实例:

public class ServerNetty{    private ServerBootstrap bootstrap=null;    private EventLoopGroup group=null;    public void init(){        group=new NioEventLoopGroup(1);//线程数量为 1        bootstrap.group(group,group);    }}
3.2 多线程配置

在 ServerBootstrap 调用方法 group 的时候,传递的参数是两个不同的线程组,负责监听的 acceptor 线程组的线程数为 1,负责处理客户端线程组的线程数大于 1。

实例:

public class ServerNetty{    private ServerBootstrap bootstrap=null;    private EventLoopGroup acceptorGroup=null;    private EventLoopGroup clientGroup=null;    public void init(){        acceptorGroup=new NioEventLoopGroup(1);//线程数量为 1        clientGroup=new NioEventLoopGroup();//默认是 cpu 的核心数        bootstrap.group(acceptorGroup,clientGroup);    }}
3.3 主从多线程配置

在 ServerBootstrap 调用方法 group 的时候,传递的参数是两个不同的线程组,负责监听的 acceptor 线程组的线程数大于 1,负责处理客户端线程组的线程数大于 1。

实例:

public class ServerNetty{    private ServerBootstrap bootstrap=null;    private EventLoopGroup acceptorGroup=null;    private EventLoopGroup clientGroup=null;    public void init(){        acceptorGroup=new NioEventLoopGroup();//默认是 cpu 的核心数        clientGroup=new NioEventLoopGroup();//默认是 cpu 的核心数        bootstrap.group(acceptorGroup,clientGroup);    }}
4. 自定义任务队列

通常情况下,任务队列中常见的任务主要有以下几种类型:

用户自定义的异步任务,比如:依赖线程池去异步某个任务等;用户自定义的定时任务,比如:依赖定时线程池去定义每隔 n 秒执行某个任务等;非当前 reactor 线程调用 channel 的各种方法。4.1 异步任务

其实跟我们平时使用线程池没有什么区别,只不过调用的是底层 Netty 线程组。

实例:

//使用 reactor 线程的异步任务ctx.channel().eventLoop().execute(new Runnable() {    @Override    public void run() {        //...    }});//使用线程池去实现异步任务ExecutorService es = Executors.newFixedThreadPool(5);es.execute(new Runnable() {    @Override    public void run() {            }});
4.2 定时任务

其实类似我们平时使用的定时任务线程池(如:ScheduledThreadPool),只不过是调用底层 Netty 线程组。

实例:

//使用 reactor 线程实现的定时任务ctx.channel().eventLoop().schedule(new Runnable() {    @Override    public void run() {    }}, 60, TimeUnit.SECONDS);//使用线程池去实现定时任务ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);ses.schedule(new Runnable() {    public void run() {        System.out.println("i:" + temp);    }}, 3, TimeUnit.SECONDS);

总结:

当前 reactor 线程调用当前 eventLoop 执行任务,直接执行,否则,添加到任务队列稍后执行;netty 内部的任务分为普通任务和定时任务,分别落地到 MpscQueue 和 PriorityQueue;netty 每次执行任务循环之前,会将已经到期的定时任务从 PriorityQueue 转移到 MpscQueue;netty 每隔 64 个任务检查一下是否该退出任务循环。5. 小结

本节主要掌握的核心知识点

Netty 的模型的理解,以及每个 NioEventLoop 所执行的三个核心操作,分别是①轮询出 IO 事件;②处理 IO 事件;③处理任务队列;了解 Channel、ChannelPipeline、ChannelHandler 之间的关系,以及 NioEventLoop 主要负责处理每个 Channel 的业务逻辑;Netty 如何配置三种 Reactor 模型;如何使用内置的 NioEventLoop 执行自定义的异步任务和定时任务。

标签: #netty业务线程池设置