Netty(1)线程模型

|▌冷眼眸甩不掉的悲伤 提交于 2020-03-09 05:00:35

前言

对于Netty框架的学习
前置知识点:线程模型

目录

  1. 线程模型概述
  2. 传统阻塞IO线程模型
  3. Reactor基本思想
  4. 单Reactor单线程
  5. 单Reactor多线程
  6. 主从Reactor多线程
  7. 总结

线程模型概述

在学习Netty线程模型之前,先要搞清楚各个线程模型的发展过程,再进行Netty线程模型的了解

现有的线程模型:

  1. 传统阻塞IO线程模型(也就是BIO)
  2. Reactor 模式

其中Reactor模式根据Reactor的数量和线程的数量可以分为三种:

  1. 单Reactor单线程
  2. 单Reactor多线程
  3. 主从Reactor多线程

Netty框架是基于主从Reactor多线程模型进行改进(多个主Reactor)

传统阻塞IO线程模型

传统阻塞IO也就是Java BIO
很简单,就是一个连接一个线程的模型
在这里插入图片描述

每一个连接都创建一个线程去处理,而且当完成连接,读取数据时,如果没有数据可读会阻塞线程

传统阻塞IO线程模型缺点:

  • 对于高并发的环境,会创建很多线程,系统开销大
  • 阻塞IO模式会造成线程浪费

Reactor基本思想

Reactor模式是对传统阻塞IO模型的一种改进

其中基本思想有两个:

  1. 基于 I/O 复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象等待,无需阻塞等待所有连接。当某个连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理

  2. 基于线程池复用线程资源:不必再为每个连接创建线程,将连接完成后的业务处理任务分配给线程进行处理,一个线程可以处理多个连接的业务。

I/O 复用模型与线程池复用线程资源(基本思想):

在这里插入图片描述

Reactor模式:对于多个Client请求,Reactor使用IO复用监听事件ServiceHandler处理多个请求(基于事件驱动),然后分发给某个线程

核心组件:

  • Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。
    它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人;
  • Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor
    通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作

Reactor模式让我想起了Java IO 的发展:
在这里插入图片描述
伪异步IO就是线程池复用线程,NIO基于IO复用模型
这种思想体现在其他网络编程中

单Reactor单线程

Java网络编程(9)NIO - 群聊系统

前面写的群聊系统其实就是一个单Reactor单线程模式
在这里插入图片描述
我们的群聊系统中:
设置了Selector的select()方法负责监听(起到了Reactor的作用)
ServerSocketChannel监听端口号,连接实现accept方法
对于监听的事件进行了处理(使用的是方法,而不是创建对象)
handler对象中的处理方法read就是key.isReadable()判断处理事件

而且服务器仅在一个main线程中执行

优缺点:
优点:模型简单,没有多线程、进程通信、竞争的问题,全部都在一个线程中完成

缺点:

  1. 性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。Handler 在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈

  2. 可靠性问题,线程意外终止,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障

适用场景:客户端数目有限,业务处理快的情况

单Reactor多线程

相对于单Reactor单线程,引进了一个线程池,分出线程来处理业务,Reactor线程仅负责接收连接和响应事件,具体事件有线程池分配的线程处理

在这里插入图片描述

具体的步骤:

  1. 多个客户端发出连接请求
  2. Reactor主线程中Reactor对象的select方法监控客户端请求事件,再由dispatch分发事件到相应的处理对象
  3. 如果是请求连接事件,分发到Acceptor,Acceptor通过accept方法处理连接请求,然后创建一个handle对象处理接下来会发生的事件(类似ServerSocket)
  4. 如果不是请求连接事件,dispatch分发到相应的handle对象中
  5. handle对象仅响应事件,通过read读取数据后,分发到Worker线程池相应的线程处理业务
  6. Worker线程池会分配线程处理业务,然后将结果返回handle
  7. handle对象send结果给客户端

大致的步骤就是这样,单Reactor多线程仅多了一个线程池,将业务的处理分割开

优缺点:
优点:可以充分利用到多核CPU
缺点:多线程数据共享和访问比较复,而且对于单Reactor单线程的性能问题并没有解决, Reactor 处理所有的事件的监听和响应,一样在高并发会出现性能问题

主从Reactor多线程

主从Reactor多线程模式与单Reactor多线程的区别在与将Reactor分为Reactor主线程和Reactor子线程
在这里插入图片描述

它将服务器分成了3层:Reactor主线程、Reactor子线程(可以多个)、线程池

这就解决了性能问题,Reactor主线程仅负责监听连接与连接事件,其他事件的处理交给Reactor子线程

具体步骤:

  1. 客户端发出连接请求
  2. Reactor主线程的MainReactor对象通过select方法监听连接事件,当有连接事件时,通过Acceptor对象处理连接
  3. Acceptor处理完连接后,MainReactor将连接分配给SubReactor
  4. SubReactor将连接加入连接队列,select方法监听事件,并创建handle处理事件
  5. 当有事件发生,SubReactor调用handle对象处理事件
  6. handle对象通过read读取数据,分发给Worker线程池处理业务
  7. Worker线程池分配独立的线程处理业务,并将结果返回给handle
  8. handle将结果send给客户端
  9. 如果Client过多,MainReactor可以关联多个SubReactor

优缺点:
优点:

  1. 父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。
  2. 父线程与子线程的数据交互简单,Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。

缺点:编程复杂度较高

总结

  1. 线程模型可以分为传统阻塞IO模型与Reactor模型
  2. Reactor模型的基本思想是:IO复用模型和线程池复用线程资源
  3. Reactor分为3种:单Reactor单线程模型、单Reactor多线程模型、主从Reactor多线程模型
  4. Netty是对主从Reactor多线程模型的修改,即可以多个Reactor主线程
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!