赞
踩
哔哩哔哩黑马程序员 netty实战视频
NIO(New I/O)是Java中提供的一种基于通道和缓冲区的I/O(Input/Output)模型。它是相对于传统的IO(InputStream和OutputStream)模型而言的新型I/O模型。NIO的主要特点包括:
1.通道与缓冲区:
2.NIO引入了通道(Channel)和缓冲区(Buffer)的概念。通道是对传统IO中的流的抽象,它可以支持双向数据传输。而缓冲区则是存储数据的地方,数据在通道和缓冲区之间传递。
3.非阻塞IO:
4.NIO提供了非阻塞I/O操作的能力。在传统IO模型中,当一个线程在读取或写入数据时会被阻塞,而在NIO中,线程可以继续处理其他任务,而不必等待数据的读取或写入完成。
5.选择器(Selector):
6.NIO引入了选择器的概念,使得一个线程可以同时监控多个通道的IO事件。这样,一个线程可以有效地管理多个通道,从而提高系统的性能。
7.面向缓冲区的操作:
8.NIO中的数据读取和写入都是面向缓冲区的。数据首先被读取到缓冲区,然后再从缓冲区写入到通道,或者从通道读取到缓冲区。这种方式相对于直接流式IO更加灵活,可以更好地处理不同大小的数据块。
9.异步IO:
10.Java NIO提供了异步I/O操作的支持。通过使用Future、Callback等机制,可以实现异步的IO操作,使得程序可以在数据读取或写入的同时执行其他任务。
11.多路复用:
12.多路复用是NIO的一个重要特性,通过选择器可以实现同时管理多个通道的IO操作。这在高并发的网络应用中特别有用。
channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前的 stream 要么是输入,要么是输出,channel 比 stream 更为底层
常见的 Channel 有
buffer 则用来缓冲读写数据,常见的 buffer 有
selector 单从字面意思不好理解,需要结合服务器的设计演化来理解它的用途
selector 的作用就是配合一个线程来管理多个 channel,获取这些 channel 上发生的事件,这些 channel 工作在非阻塞模式下(不会因为单个线程的堵塞而失去效果),不会让线程吊死在一个 channel 上。适合连接数特别多,但流量低的场景(low traffic)
调用 selector 的 select() 会阻塞直到 channel 发生了读写就绪事件,这些事件发生,select 方法就会返回这些事件交给 thread 来处理
有一普通文本文件 data.txt,内容为
1234567890abcd
使用 FileChannel 来读取文件内容
@Slf4j public class ChannelDemo1 { public static void main(String[] args) { try (RandomAccessFile file = new RandomAccessFile("helloword/data.txt", "rw")) { FileChannel channel = file.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(10); do { // 向 buffer 写入 int len = channel.read(buffer); log.debug("读到字节数:{}", len); if (len == -1) { break; } // 切换 buffer 读模式 buffer.flip(); while(buffer.hasRemaining()) { log.debug("{}", (char)buffer.get()); } // 切换 buffer 写模式 buffer.clear(); } while (true); } catch (IOException e) { e.printStackTrace(); } } }
输出
10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 读到字节数:10 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 1 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 2 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 3 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 4 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 5 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 6 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 7 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 8 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 9 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 0 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 读到字节数:4 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - a 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - b 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - c 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - d 10:39:03 [DEBUG] [main] c.i.n.ChannelDemo1 - 读到字节数:-1
向 buffer 写入数据,例如调用 channel.read(buffer)
调用 flip() 切换至读模式
从 buffer 读取数据,例如调用 buffer.get()
调用 clear() 或 compact() 切换至写模式
重复 1~4 步骤
flip()
是java.nio.ByteBuffer
类中的一个方法,它用于将缓冲区的当前读取位置设置为缓冲区的开始位置,并将缓冲区的大小调整为等于缓冲区剩余的字节数。在将缓冲区中的数据写入网络或文件之前,通常需要调用
flip()
方法,以便将缓冲区中的数据移动到读取位置。这样,下一次从缓冲区中读取数据时,就可以从缓冲区的开始位置开始读取
channel
和buffer
分别是java.nio.channels.Channel
和java.nio.ByteBuffer
两个类。
Channel
类是 NIO 中的核心接口,它表示一个通信通道,如套接字、文件描述符等。它提供了一种将字节数据从一个地方读取到另一个地方的方法,可以用于网络编程、文件读写等场景。
ByteBuffer
类是 NIO 中的缓冲区类,它提供了一种高效的字节读写操作。它允许将字节数据从一个地方读取到另一个地方,同时提供了一些方法来改变当前读取和写入的位置,以及调整缓冲区的大小等。
channel.read(buffer)
语句表示从指定的channel
中读取数据到buffer
中。channel.read(buffer)
会尝试读取数据到buffer
中,直到buffer
中的字节数达到或超过buffer.capacity()
或者读取到 EOF(表示读取到了流的末尾)。如果读取到了 EOF,则返回 -1,否则返回读取到的字节数。这个语句的作用是将
channel
中的数据读取到buffer
中,从而可以对读取到的数据进行处理。如果读取到了 EOF,说明已经读取到了流的末尾,可以关闭channel
和buffer
,或者重新设置buffer
的位置,以便读取下一部分数据。
ByteBuffer 有以下重要属性
一开始
写模式下,position 是写入位置,limit 等于容量,下图表示写入了 4 个字节后的状态
flip 动作发生后,position 切换为读取位置,limit 切换为读取限制
读取 4 个字节后,状态
clear 动作发生后,状态
compact 方法,是把未读完的部分向前压缩,然后切换至写模式
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。