在NIO中有几个比较关键的概念 Channel 通道 Buffer 缓冲区 Selector 选择器 。下例是传统的IO中读取一个文件内容的方式
这里的InputStream实际上就是为读取文件提供一个通道。因此可以将NIO 中的Channel同传统IO中的Stream来类比 但在传统IO中 Stream是单向的 比如InputStream只能进行读取操作 OutputStream只能进行写操作。而Channel是双向的 既可用来进行读操作 又可用来进行写操作。Buffer 缓冲区 是NIO中非常重要的一个概念 在NIO中所有数据的读和写都离不开Buffer。比如上面的一段代码中 读取的数据是放在byte数组当中 而在NIO中 读取的数据只能放在Buffer中。同样地 写入数据也是先写入到Buffer中。NIO中最核心的一个东西是Selector Selector的作用就是用来轮询每个注册的Channel 一旦发现Channel有注册的事件发生 便获取事件然后进行处理。用单线程处理一个Selector 然后通过Selector.select()方法来获取到达事件 在获取了到达事件之后 就可以逐个地对这些事件进行响应处理。
2. ChannelChannel和传统IO中的Stream很相似 但也有很大的区别 主要区别为 通道是双向的 通过一个Channel既可以进行读 也可以进行写 而Stream只能进行单向操作 通过一个Stream只能进行读或者写。以下是常用的几种通道 这些通道涵盖了UDP 和 TCP 网络IO 以及文件IO
FileChannel 通过使用FileChannel可以从文件读或向文件写入数据 SocketChanel 通过SocketChannel 以TCP来向网络连接的两端读写数据 ServerSocketChannel 通过ServerSocketChanel能够监听客户端发起的TCP连接 并为每个TCP连接创建一个新的SocketChannel来进行数据读写 DatagramChannel 通过DatagramChannel 以UDP协议来向网络连接的两端读写数据。下面实例为通过FileChannel向文件中写入数据
运行结果
3. BufferBuffer 缓冲区 实际上是一个容器。Channel提供从文件、网络读取数据的渠道 但是读取或写入的数据都必须经由Buffer。在NIO中 Buffer是一个顶层父类 它是一个抽象类 常用的Buffer的子类有
ByteBufferIntBufferCharBufferLongBufferDoubleBufferFloatBufferShortBuffer这些Buffer覆盖了能通过IO发送的基本数据类型 byte, short, int, long, float, double 和 char。如果是对于文件读写 上面几种Buffer都可能会用到 对于网络读写来说 用的最多的是ByteBuffer。
Buffer通过几个变量来保存这个数据的当前位置状态 也就是有四个索引
ByteBuffer.allocate(11)创建了一个11个byte的数组缓冲区 初始状态如下 position的位置为0 capacity和limit默认为数组长度。当写入5个字节时 位置变化如下图所示 这时需要将缓冲区的5个字节数据写入channel通信信道 调用byteBuffer.flip()方法 位置变化如下 下一次写数据之前调用clear()方法即可4. SelectorSelector允许单线程处理多个 Channel。Selector能够检测多个注册的通道上是否有事件发生 如果有事件发生 便获取事件然后针对每个事件进行相应的响应处理。这样一来 只用一个单线程就可以管理多个通道 也就是管理多个连接。这样使得只有在连接真正有读写事件发生时 才会调用函数来进行读写 就大大地减少了系统开销 并且不必为每个连接都创建一个线程 不用去维护多个线程 并且避免了多线程之间的上下文切换导致的开销。与Selector有关的一个关键类是SelectionKey 一个SelectionKey表示一个到达的事件 这2个类构成了服务端处理业务的关键逻辑。
5. 与传统IO的区别面向流与面向缓冲 Java IO面向流意味着每次从流中读一个或多个字节 直至读取所有字节 它们没有被缓存在任何地方。此外 它不能前后移动流中的数据。如果需要前后移动流中的数据 需要先将它缓存到一个缓冲区。Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区 需要时可在缓冲区中前后移动 增加了处理过程中的灵活性。但是 还需要检查是否该缓冲区中包含所有需要处理的数据。而且 需确保当更多的数据读入缓冲区时 不要覆盖缓冲区里尚未处理的数据。阻塞与非阻塞IO Java IO的各种流是阻塞的。这意味着 当一个线程调用read() 或 write()时 该线程会被阻塞直到有数据被读取 或数据完全写入。该线程在此期间不能再干任何事情。Java NIO的非阻塞读模式 使一个线程从某通道发送请求读取数据 它仅能读到目前可用的数据 如果目前没有数据可用时 不会阻塞 直至数据变的可以读取之前 该线程可以继续做其他的事情。非阻塞写也是如此。一个线程请求写入一些数据到某通道 但不需要等待它完全写入 这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作 所以一个单独的线程现在可以管理多个输入和输出通道 channel 。选择器 Java NIO的选择器允许一个单独的线程来监视多个输入通道 使用一个单独的线程来选择通道 这些通道里已经有可以处理的输入 或者选择已准备写入的通道。这种选择机制 使得一个单独的线程很容易来管理多个通道。前提条件 请您在购买前确保已完成注册和充值。详细操作请参见 如何注册公有云管...
2021年3月24日,主题为《数据的世界,世界的数据》的星环科技2021春季新品发布会...
建站 什么 虚拟主机 够用?这要看搭建的是什么类型的网站。比如个人博客类型的网...
信息化2.0时代提出开展智慧教育创新发展行动。2019年2月,中共中央、国务院印发...
在Python语言中有如下3种方法: 成员方法 类方法(classmethod) 静态方法(staticm...
【51CTO.com快译】 数据可视化工具不断发展,提供更强大的功能,同时改善可访问...
摘要 元旦期间 订单业务线 告知 推送系统 无法正常收发消息,作为推送系统维护者...
本文整理自直播《Hologres 数据导入/导出实践-王华峰(继儒)》 视频链接: https:/...
从 10.0.0 版开始,异步迭代器就出现在 Node 中了,在本文中,我们将讨论异步迭...
Docker生成新镜像版本的两种方式 There are two ways Docker can generate new m...