Java并发 -- Netty线程模型
BIO
- BIO即阻塞式IO,使用BIO模型,一般会为每个Socket分配一个独立的线程
- 为了避免频繁创建和销毁线程,可以采用线程池,但Socket和线程之间的对应关系不会发生变化
- BIO适用于Socket连接不是很多的场景,但现在上百万的连接是很常见的,而创建上百万个线程是不现实的
- 因此BIO线程模型无法解决百万连接的问题
- 在互联网场景中,连接虽然很多,但每个连接上的请求并不频繁,因此线程大部分时间都在等待IO就绪
理想的线程模型
- 用一个线程来处理多个连接,可以提高线程的利用率,降低所需要的线程
- 使用BIO相关的API是无法实现的,BIO相关的Socket读写操作都是阻塞式的
- 一旦调用了阻塞式的API,在IO就绪前,调用线程会一直阻塞,也就无法处理其他的Socket连接
- 利用NIO相关的API能够实现一个线程处理多个连接,通过Reactor模式实现
Reactor模式
- Handle指的是IO句柄,在Java网络编程里,本质上是一个网络连接
- Event Handler是事件处理器,handle_event()处理IO事件,每个Event Handler处理一个IO Handle
- get_handle()方法可以返回这个IO Handle
- Synchronous Event Demultiplexer相当于操作系统提供的_IO多路复用API_
- 例如POSIX标准里的select()以及Linux里的epoll()
- Reactor是Reactor模式的核心
- register_handler()和remove_handler()可以注册和删除一个事件处理器
- handle_events()是核心
- 通过同步事件多路选择器提供的select()方法_监听网络事件_
- 当有网络事件就绪后,就遍历事件处理器来处理该网络事件
1 | void Reactor::handle_events(){ |
Netty的线程模型
- Netty参考了Reactor模式,Netty中最核心的概念是事件循环(EventLoop),即Reactor模式中的Reactor
- 负责监听网络事件并调用事件处理器进行处理
- 在Netty 4.x中,网络连接 : EventLoop : Java线程 = N:1:1
- 所以,_一个网络连接只会对应到一个Java线程_
- 优点:对于一个网络连接的事件处理都是单线程的,这样能避免各种并发问题
EventLoopGroup
- EventLoopGroup由一组EventLoop组成
- 实际使用中,一般会创建两个EventLoopGroup,一个是bossGroup,一个是workerGroup
- Socket处理TCP网络连接请求,是在一个独立的Socket中
- 每当有一个TCP连接成功建立,都会创建一个新的Socket
- 之后对TCP连接的读写都是由新创建处理的Socket完成的
- 处理TCP连接请求和读写请求是通过两个不同的Socket完成的
- 在Netty中,bossGroup用来处理连接请求的,workerGroup用来处理读写请求的
- bossGroup处理完连接请求后,会将这个连接提交给workerGroup来处理
- workerGroup中会有多个EventLoop,通过均衡负载算法(轮询)来分配某一个EventLoop
Echo程序
1 | public class Echo { |
参考资料
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.