网络通信
- 传统的IO 流都是阻塞式的。也就是说,当一个线程调用read() 或write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
- Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞IO 的空闲时间用于在其他通道上执行IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端
使用 NIO 完成网络通信的三个核心:
- 通道(Channel):负责连接
java.nio.channels.Channel 接口:
SelectableChannel
SocketChannel
ServerSocketChannel
DatagramChannel
Pipe.SinkChannel
Pipe.SourceChannel - 缓冲区(Buffer):负责数据的存取
- 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况
阻塞式示例
详见Githubjava-learning项目
非阻塞式
选择器(Selector)
选择器(Selector)是SelectableChannle 对象的多路复用器,Selector 可以同时监控多个SelectableChannel 的IO 状况,也就是说,利用Selector 可使一个单独的线程管理多个Channel。Selector 是非阻塞IO 的核心
- 创建Selector :通过调用Selector.open() 方法创建一个Selector。
- 向选择器注册通道:SelectableChannel.register(Selector sel, int ops)
- 当调用register(Selector sel, int ops) 将通道注册选择器时,选择器对通道的监听事件,需要通过第二个参数ops 指定
- 可以监听的事件类型(可使用SelectionKey 的四个常量表示):
读: SelectionKey.OP_READ (1)
写: SelectionKey.OP_WRITE (4)
连接: SelectionKey.OP_CONNECT(8)
接收: SelectionKey.OP_ACCEPT (16) - 若注册时不止监听一个事件,则可以使用“位或”操作符连接
socketChannel serverSocketChannel非阻塞式示例代码
详见Githubjava-learning项目
管道(Pip)
Java NIO 管道是2个线程之间的单向数据连接。
Pipe有一个source通道和一个sink通道。数据会
被写到sink通道,从source通道读取