Netty实战与源码剖析(三)——Netty线程模型

简介: Netty实战与源码剖析(三)——Netty线程模型

1 线程模型基本介绍


不同的线程模式,对于程序的性能有很大的影响,Netty为何具有如此高的性能,很大程度上是得益于Netty采用的线程模型。


目前主流存在的线程模型有两种:


传统阻塞IO模型

Reactor模型

然而根据Reactor的数量和处理资源线程的数量不同,又可以将Reactor模型分为三种:


单Reactor 单线程

单Reactor 多线程

主从Reactor 多线程


Netty基于主从Reactor多线程模型做了一定的改进,其中主从Reactor多线程模型有多个Reactor。


1.1 传统阻塞IO模型


工作原理图:


939c8d954d324874ac5b725a9020f470.png

模型特点:


采用阻塞IO模式获取输入的数据

每个连接都要独立的线程来完成数据的输入、业务处理、数据的输出返回

问题分析:


当并发度很大,就会创建大量的线程,占用很大的系统开销

当连接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在read操作,造成线程资源的浪费


解决方案:


基于IO复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象等待,无需阻塞等待所有连接。当某个连接有数据可用时,操作系统通知应用程序,线程从阻塞状态返回,处理业务逻辑。


基于线程池复用线程资源:不必再为每个连接创建一个线程,将连接完成后的业务处理交给线程,这样可以使得线程池中的每一个线程都可以处理多个连接的业务逻辑。


1.2 Reactor模式


上述说的IO复用模型结合线程池机制,就形成了Reactor模式。


工作原理图:


image.png


模型特点:


Reactor模式是通过一个或多个输入同时传递给服务处理器的模式,基于事件驱动

服务端程序处理连接的多个请求,并把请求分派给相应的处理线程,故Reactor模式也叫Dispatcher模式

Reactor模式使用IO复用模型,监听事件,收到事件后,分发给某个线程或进程,这也是网络服务器高并发处理的关键


核心组件:


Reactor:其实就是上图中的ServiceHandler

Handler:其实就是上图中处理线程的EventHandler


1.3 单Reactor单线程模式


前面的博客中,Java NIO编程其实就是一种单Reactor单线程,Selector相当于Reactor,得到SelectKey后的操作其实就是在一个线程中完成的,这就是一个Handler。


优点:模型简单,无多线程、线程通信、上下文切换、锁竞争等问题


缺点


性能低,只用了一个线程,无法完全发挥多核CPU的性能

可用性低,线程若意外终止,或进入死循环,导致整个通信模块不可用


使用场景:客户端数量有限,业务处理快速等


1.4 单Reactor多线程模式


和单Reactor单线程模式比较类似,不同的地方在于,当Reactor收到事件,如果是连接事件,则交给一个特定的线程处理连接后的业务;如果不是连接时间,则由Reactor分发到不同的Handler,但Handler只负责相应事件,不做具体的业务处理,只是通过read读取数据后,交给worker线程池进行处理业务,worker线程池会分配一个线程来处理业务,并将结果返回给Handler,Handler再返回结果给客户端。


优点:充分利用多核CPU的处理能力


缺点


多线程数据共享和访问较为复杂,线程安全问题;

Reactor是单线程中运行的,处理所有的事件监听和相应,高并发下有性能瓶颈


1.5 主从Reactor多线程模式


Reactor主线程MainReactor对象通过select监听连接事件,收到连接事件后,则交给一个特定的线程处理连接后的业务;如果是其他事件,MainReactor会将事件分配给从线程的SubReactor对象,然后SubReactor将事件分发到不同的Handler,但Handler只负责相应事件,不做具体的业务处理,只是通过read读取数据后,交给worker线程池进行处理业务,worker线程池会分配一个线程来处理业务,并将结果返回给Handler,Handler再返回结果给客户端。


优点:父线程与子线程的数据交互简单,职责明确,父线程只需要接受新连接,子线程则完成后续的业务逻辑处理;父子线程数据交互简单,主线程只需要把非连接的事件传递给子线程,子线程无需返回数据


缺点:复杂度高


这种模型在许多项目中广泛使用,包括Nginx主从Reactor多进程模型,Memcached主从多线程,Netty主从多线程模型的支持。


2 Netty线程模型


如同所示:

image.png


Netty 抽象出两组线程池:BossGroup 和 WorkerGroup,也可以叫做 BossNioEventLoopGroup 和 WorkerNioEventLoopGroup。每个线程池中都有 NioEventLoop 线程。BossGroup 中的线程专门负责和客户端建立连接,WorkerGroup 中的线程专门负责处理连接上的读写。BossGroup 和 WorkerGroup 的类型都是 NioEventLoopGroup。


NioEventLoopGroup 相当于一个事件循环组,这个组中含有多个事件循环,每个事件循环就是一个 NioEventLoop。


NioEventLoop 表示一个不断循环的执行事件处理的线程,每个 NioEventLoop 都包含一个 Selector,用于监听注册在其上的 Socket 网络连接(Channel)。


NioEventLoopGroup 可以含有多个线程,即可以含有多个 NioEventLoop。


每个 BossNioEventLoop 中循环执行以下三个步骤:


select:轮训注册在其上的 ServerSocketChannel 的 accept 事件(OP_ACCEPT 事件)

processSelectedKeys:处理 accept 事件,与客户端建立连接,生成一个 NioSocketChannel,并将其注册到某个 WorkerNioEventLoop 上的 Selector 上

runAllTasks:再去以此循环处理任务队列中的其他任务


每个 WorkerNioEventLoop 中循环执行以下三个步骤:


select:轮训注册在其上的 NioSocketChannel 的 read/write 事件(OP_READ/OP_WRITE 事件)

processSelectedKeys:在对应的 NioSocketChannel 上处理 read/write 事件

runAllTasks:再去以此循环处理任务队列中的其他任务


在以上两个processSelectedKeys步骤中,会使用 Pipeline(管道),Pipeline 中引用了 Channel,即通过 Pipeline 可以获取到对应的 Channel,Pipeline 中维护了很多的处理器(拦截处理器、过滤处理器、自定义处理器等)。

目录
打赏
0
0
0
0
6
分享
相关文章
面试必问的多线程优化技巧与实战
多线程编程是现代软件开发中不可或缺的一部分,特别是在处理高并发场景和优化程序性能时。作为Java开发者,掌握多线程优化技巧不仅能够提升程序的执行效率,还能在面试中脱颖而出。本文将从多线程基础、线程与进程的区别、多线程的优势出发,深入探讨如何避免死锁与竞态条件、线程间的通信机制、线程池的使用优势、线程优化算法与数据结构的选择,以及硬件加速技术。通过多个Java示例,我们将揭示这些技术的底层原理与实现方法。
137 3
Java并发编程实战:使用synchronized关键字实现线程安全
Java并发编程实战:使用synchronized关键字实现线程安全
93 0
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
87 12
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
105 8
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
什么是线程池?从底层源码入手,深度解析线程池的工作原理
本文从底层源码入手,深度解析ThreadPoolExecutor底层源码,包括其核心字段、内部类和重要方法,另外对Executors工具类下的四种自带线程池源码进行解释。 阅读本文后,可以对线程池的工作原理、七大参数、生命周期、拒绝策略等内容拥有更深入的认识。
204 29
探索Python的并发编程:线程与进程的实战应用
【10月更文挑战第4天】 本文深入探讨了Python中实现并发编程的两种主要方式——线程和进程,通过对比分析它们的特点、适用场景以及在实际编程中的应用,为读者提供清晰的指导。同时,文章还介绍了一些高级并发模型如协程,并给出了性能优化的建议。
65 3
|
5月前
|
Reactor实战,创建一个简单的单线程Reactor(理解了就相当于理解了多线程的Reactor)
本文通过一个简单的单线程Reactor模式的Java代码示例,展示了如何使用NIO创建一个服务端,处理客户端的连接和数据读写,帮助理解Reactor模式的核心原理。
68 0
Reactor实战,创建一个简单的单线程Reactor(理解了就相当于理解了多线程的Reactor)
源码解密协程队列和线程队列的实现原理(一)
源码解密协程队列和线程队列的实现原理(一)
70 1
源码解密协程队列和线程队列的实现原理(二)
源码解密协程队列和线程队列的实现原理(二)
51 1
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等