概要:本文阐述我对NIO中的一些基本概念的理解:Selector、Channel、Buffer、同步与异步、阻塞与非阻塞、多路复用。其中selector与channel进行交互,channel与buffer进行交互。
Selector
Selector是SelectableChannel 对象的多路复用器。Selector可以同时监控多个SelectableChannel的IO状况,也就是说,利用 Selector可使一个单独的线程管理多个 Channel。
SelectionKey:表示某个SelectableChannel和Selector之间的注册关系。selector可以监听多个channel的多个事件。
//把channel注册到selector,selector监听该channel的4类事件,最后返回注册关系key
SelectionKey key = channel.register(selector,SelectionKey.OP_READ|SelectionKey.OP_WRITE|SelectionKey.OP_CONNECT|SelectionKey.OP_ACCEPT);
Set<SelectionKey> keys = selector.keys();//获取所有的 SelectionKey 集合。代表注册在该Selector上的所有Channel
Set<SelectionKey> selectedKeys = selector.selectedKeys();//返回此Selector的已选择键集
Channel
Channel表示打开到 IO 设备(例如:文件、套接字)的连接。
Channel 类似于传统的“流”。应用程序不能直接从channel中读写数据,需要通过Buffer进行数据交互。
Buffer
Buffer(即缓冲区)是一个用于特定基本数据类型的容器。缓冲区就是数组,用于存储不同数据类型的数据。可以通过API操作缓冲区,对数据进行处理。
Buffer与Channel的关系:Channel 负责传输, Buffer 负责存储,数据是从通道读入缓冲区,或者从缓冲区写入通道中的。若使用 NIO 系统,需要获取用于连接 IO设备的通道以及用于容纳数据的缓冲区。
分散读取:将通道中的数据分散到多个buffer中。可以用多个buffer读取1个channel中的数据,伪代码:channel.read(ByteBuffer[] bufs);
聚集写入:将多个buffer中的数据聚集写到1个通道中。伪代码:channel.write(ByteBuffer[] bufs);
同步与异步
同步和异步都是基于应用程序和操作系统处理 IO 事件所采用的方式。
同步:应用程序要直接参与IO读写的操作,应用程序必须阻塞在某个方法上面等待操作系统处理IO事件完成:阻塞IO事件(BIO)或者通过轮询IO事件(NIO)。
异步:所有的IO读写交给操作系统去处理,应用程序可以去做其他的事情,当操作完成 IO 后,会给应用程序一个通知。AIO就是异步处理IO操作。
阻塞与非阻塞
阻塞与非阻塞表示线程在访问数据时,数据未准备就绪时的一种处理方式。
阻塞:当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。
非阻塞:当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。
多路复用
1个selector可以注册多个channel。selector线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的selector线程可以管理多个输入和输出通道。因此,NIO可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。