文章目录
- 概述
- Channel & Buffer
- Selector
- 服务器设计历史演化
- 多线程版设计
- 线程池版设计
- selector 版设计
概述
NIO的意思是 non-blocking io 非阻塞 IO 。NIO中存在3大组件:Channel 、 Buffer 、Selector
Channel & Buffer
channel (中文 管道的意思)有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer(中文 缓冲区的意思),也可以将 buffer 的数据写入 channel,而之前的 stream 要么是输入,要么是输出,channel 比 stream 更为底层。Channel和Buffer是多对多的关系,它们相互协作共同完成数据的传输和处理任务。
常见的 Channel 有
- FileChannel (文件管道,不支持非阻塞)
- DatagramChannel
- SocketChannel (网络管道,支持非阻塞)
- ServerSocketChannel (服务端网络管道,支持非阻塞)
buffer 则用来缓冲读写数据,常见的 buffer 有
- ByteBuffer
- MappedByteBuffer
- DirectByteBuffer
- HeapByteBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
- CharBuffer
Selector
selector 中文就是选择器的意思,单从字面意思不好理解,需要结合服务器的设计演化来理解它的用途。服务器的设计演化从多线程->线程池selector
服务器设计历史演化
多线程版设计
在多线程版本下,一个请求到达服务端,服务端开辟一个线程去处理该请求,这种做法在请求量不多的情况下可以接受,但是一旦请求量多了那么问题随之而来,内存占用高、线程上下文切换成本高这些问题会让你的服务器最终崩溃。
线程池版设计
在线程池版本下,服务器会初始化一个线程池,池内会有一定量的线程,当请求达到服务器时会使用线程池内的线程进行处理,处理完归还给线程池。这种模式下虽然避免了服务器不停地创建线程、销毁线程,但是仍然存在问题:线程仅能处理一个 socket 连接,当处理某个socket时线程就会阻塞等待处理完成才能继续处理其他任务。
selector 版设计
在selector 模式下,当一个请求到达服务器时,会先和channel进行关联,由selector来管理这些channel什么时候提交给线程处理。这些 channel 工作在非阻塞模式下,有了selector就不会让线程吊死在一个 channel 上。适合连接数特别多,但流量低的场景。调用 selector 的 select() 会阻塞直到 channel 发生了读写就绪事件,这些事件发生,select 方法就会返回这些事件交给 thread 来处理。