当前位置:主页 > 查看内容

一文助你“把握”NIO——《我的Java打怪日记》

发布时间:2021-07-19 00:00| 位朋友查看

简介:NIO1. 基础概念 在NIO中有几个比较关键的概念 Channel 通道 Buffer 缓冲区 Selector 选择器 。下例是传统的IO中读取一个文件内容的方式 这里的InputStream实际上就是为读取文件提供一个通道。因此可以将NIO 中的Channel同传统IO中的Stream来类比 但在传统IO……
NIO1. 基础概念

在NIO中有几个比较关键的概念 Channel 通道 Buffer 缓冲区 Selector 选择器 。下例是传统的IO中读取一个文件内容的方式

image.png

这里的InputStream实际上就是为读取文件提供一个通道。因此可以将NIO 中的Channel同传统IO中的Stream来类比 但在传统IO中 Stream是单向的 比如InputStream只能进行读取操作 OutputStream只能进行写操作。而Channel是双向的 既可用来进行读操作 又可用来进行写操作。Buffer 缓冲区 是NIO中非常重要的一个概念 在NIO中所有数据的读和写都离不开Buffer。比如上面的一段代码中 读取的数据是放在byte数组当中 而在NIO中 读取的数据只能放在Buffer中。同样地 写入数据也是先写入到Buffer中。NIO中最核心的一个东西是Selector Selector的作用就是用来轮询每个注册的Channel 一旦发现Channel有注册的事件发生 便获取事件然后进行处理。

image.png

用单线程处理一个Selector 然后通过Selector.select()方法来获取到达事件 在获取了到达事件之后 就可以逐个地对这些事件进行响应处理。

2. Channel

Channel和传统IO中的Stream很相似 但也有很大的区别 主要区别为 通道是双向的 通过一个Channel既可以进行读 也可以进行写 而Stream只能进行单向操作 通过一个Stream只能进行读或者写。以下是常用的几种通道 这些通道涵盖了UDP 和 TCP 网络IO 以及文件IO

FileChannel 通过使用FileChannel可以从文件读或向文件写入数据 SocketChanel 通过SocketChannel 以TCP来向网络连接的两端读写数据 ServerSocketChannel 通过ServerSocketChanel能够监听客户端发起的TCP连接 并为每个TCP连接创建一个新的SocketChannel来进行数据读写 DatagramChannel 通过DatagramChannel 以UDP协议来向网络连接的两端读写数据。


下面实例为通过FileChannel向文件中写入数据

image.png

运行结果

image.png

3. Buffer

Buffer 缓冲区 实际上是一个容器。Channel提供从文件、网络读取数据的渠道 但是读取或写入的数据都必须经由Buffer。在NIO中 Buffer是一个顶层父类 它是一个抽象类 常用的Buffer的子类有

ByteBufferIntBufferCharBufferLongBufferDoubleBufferFloatBufferShortBuffer


这些Buffer覆盖了能通过IO发送的基本数据类型 byte, short, int, long, float, double 和 char。如果是对于文件读写 上面几种Buffer都可能会用到 对于网络读写来说 用的最多的是ByteBuffer。

Buffer通过几个变量来保存这个数据的当前位置状态 也就是有四个索引

image.png

ByteBuffer.allocate(11)创建了一个11个byte的数组缓冲区 初始状态如下 position的位置为0 capacity和limit默认为数组长度。

image.png

当写入5个字节时 位置变化如下图所示

image.png

这时需要将缓冲区的5个字节数据写入channel通信信道 调用byteBuffer.flip()方法 位置变化如下

image.png

下一次写数据之前调用clear()方法即可4. Selector

Selector允许单线程处理多个 Channel。Selector能够检测多个注册的通道上是否有事件发生 如果有事件发生 便获取事件然后针对每个事件进行相应的响应处理。这样一来 只用一个单线程就可以管理多个通道 也就是管理多个连接。这样使得只有在连接真正有读写事件发生时 才会调用函数来进行读写 就大大地减少了系统开销 并且不必为每个连接都创建一个线程 不用去维护多个线程 并且避免了多线程之间的上下文切换导致的开销。与Selector有关的一个关键类是SelectionKey 一个SelectionKey表示一个到达的事件 这2个类构成了服务端处理业务的关键逻辑。

image.png

5. 与传统IO的区别面向流与面向缓冲 Java IO面向流意味着每次从流中读一个或多个字节 直至读取所有字节 它们没有被缓存在任何地方。此外 它不能前后移动流中的数据。如果需要前后移动流中的数据 需要先将它缓存到一个缓冲区。Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区 需要时可在缓冲区中前后移动 增加了处理过程中的灵活性。但是 还需要检查是否该缓冲区中包含所有需要处理的数据。而且 需确保当更多的数据读入缓冲区时 不要覆盖缓冲区里尚未处理的数据。阻塞与非阻塞IO Java IO的各种流是阻塞的。这意味着 当一个线程调用read() 或 write()时 该线程会被阻塞直到有数据被读取 或数据完全写入。该线程在此期间不能再干任何事情。Java NIO的非阻塞读模式 使一个线程从某通道发送请求读取数据 它仅能读到目前可用的数据 如果目前没有数据可用时 不会阻塞 直至数据变的可以读取之前 该线程可以继续做其他的事情。非阻塞写也是如此。一个线程请求写入一些数据到某通道 但不需要等待它完全写入 这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作 所以一个单独的线程现在可以管理多个输入和输出通道 channel 。选择器 Java NIO的选择器允许一个单独的线程来监视多个输入通道 使用一个单独的线程来选择通道 这些通道里已经有可以处理的输入 或者选择已准备写入的通道。这种选择机制 使得一个单独的线程很容易来管理多个通道。
本文转自网络,原文链接:https://developer.aliyun.com/article/785432
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文

  • 周排行
  • 月排行
  • 总排行

随机推荐