java NIO理解分析与基本使用
数小钱钱的种花兔 人气:0
我前段时间的一篇博客[java网络编程——多线程数据收发并行](https://www.cnblogs.com/buptleida/p/12514450.html)总结了服务端与客户端之间的收发并行实践。原理很简单,就是针对单一客户端,服务端起两个线程分别负责read和write操作,然后线程保持阻塞等待读写执行。
事实上,这样的模式非常糟糕。因为每一个客户端在服务端需要占用两条线程,假如有1000个客户端,则需要2000+条线程。cpu需要花费大量的时间进行线程上下文切换,造成系统资源浪费。
想要缩减线程数量,先要解决阻塞问题。而NIO可以通过IO多路复用将read和write的阻塞给抹去。再配合线程池,即可实现用少量的线程支撑起上百万个客户端的连接。
## 什么是NIO
#### NIO与IO多路复用
java NIO全称java non-blocking IO。字面意思即非阻塞式IO。实际上这里的非阻塞只是宏观的说法。
关于IO模式,这里引一个别人的博客,介绍了几种IO模式的区别:
[简述同步IO、异步IO、阻塞IO、非阻塞IO之间的联系与区别](https://www.cnblogs.com/felixzh/p/10345929.html)
本博客不再赘述这些,只是想说NIO属于其中的IO复用模型。(实验室里有一本《UNIX网络编程》疫情结束回学校一定把这部分好好看看)
多路复用IO模型中,会有一个线程去不断轮询多个socket的状态,当socket有读写事件时,才来调用IO操作。因为是一个线程来管理多个socket,系统不需要建立其它线程、维护线程,只有socket就绪时,才会使用IO资源,所以它大大降低了资源占用。
java NIO中,使用selector.select()监听多个通道是否有到达事件,没有事件就一直阻塞,有事件就调用IO进行处理。
#### 三大核心
- 通道(Channel)
- 缓冲区(Buffer)
- 选择器(Selectors)
详细介绍如下
![image](http://qiniu.debrisflow.cn/20200404NIO3Bean.png)
## NIO使用举例
这里以服务端读取客户端消息的流程为例,介绍NIO的使用(完整内容只有输入,暂且不管输出)。画了一个流程图,如下所示:
![image](http://qiniu.debrisflow.cn/20200404NIORead.png)
1. 建立selector和ServerSocketChannel,并绑定注册,用于监听客户端连接请求,代码如下:
```
selector = Selector.open();
ServerSocketChannel server = ServerSocketChannel.open();
// 设置为非阻塞
server.configureBlocking(false);
// 绑定本地端口
server.socket().bind(new InetSocketAddress(port));
// 注册客户端连接到达监听
server.register(selector, SelectionKey.OP_ACCEPT);
```
同时还要建立readSelector和writeSelector。其实线程池也是提前建立的,这里暂且不写。
```
readSelector = Selector.open();
writeSelector = Selector.open();
```
2. 监听通道,得到客户端,并建立SocketChannel,用于监听后续客户端消息
```
//select()方法返回已就绪的通道数
if (selector.select() == 0) {
continue;
}
Iterator
加载全部内容