Java NIO介绍及说明
2023-05-04 19:58:23 0 举报
AI智能生成
Java NIO 主要包含以下几个部分: 1. 缓冲区(Buffer):缓冲区是一个在内存中预留一块区域,用于存放读取或写入数据的区域。Java NIO 中的缓冲区类似于数组,可以读取和写入数据,同时支持更高效的数据操作。 2. 通道(Channel):通道是 Java NIO 中的另一个重要概念,用于对缓冲区数据的读取和写入。与传统的 Java I/O 中的流(Stream)不同,通道可以同时进行读和写操作,并且可以从缓冲区读取数据,也可以将数据写入到缓冲区中。 3. 选择器(Selector):选择器是 Java NIO 中的另一个重要概念,用于监控多个通道的事件状态(如连接请求、数据到达等)。选择器可以帮助我们避免使用线程池等多线程机制,从而实现更高效的 I/O 操作。 Java NIO 还提供了众多的用于处理网络和文件 I/O 的类和接口,如 SocketChannel、ServerSocketChannel、DatagramChannel、FileChannel、CharsetDecoder 等,这些类和接口的组合能够实现高效的 I/O 操作。
作者其他创作
大纲/内容
每次从流中读取一个或多个字节
没有被缓存在任何地方
不能前后移动流中的数据
传统IO面向流(字节流和字符流)
数据读取到一个稍后处理的缓冲区
需要时可在缓冲区中前后移动
需要检查缓冲区中是否包含需要处理的数据
需确保当更多数据读入缓冲区时,不覆盖缓冲区里未处理的数据
NIO 面向缓冲区(缓冲导向)
当一个线程 read() 或 write() 时,该线程阻塞直到一些数据被读取或数据完全写入
在此期间不能再干别的事情(被阻塞)
传统IO的各种流是阻塞的
仅能得到目前可用的数据
如果目前没有数据可用,就什么都不会读取
在数据变得可读取之前,线程可以做其他工作
非阻塞读
不需要等待数据完全写入
写入到缓冲区
非阻塞写
一个线程可以管理多个输入输出通道
通常将非阻塞IO的空闲时间用于在其他通道上执行IO操作
NIO是非阻塞的
vs 传统IO
Channel 是双向的,可写可读
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
主要实现
描述
channel.configureBlocking(false)
在非阻塞的信道上调用一个方法总是会立即返回
如果有连接请求,则返回客户端 SocketChannel
如果没有请求,返回 null
在一个非阻塞式的 ServerSocketChannel 上调用 accept() 方法
返回值表示所请求的操作的完成程度
配置为非阻塞
null
非阻塞模式下立刻返回
有连接则返回 SocketChannel
accept() 方法
条件 buf.hasRemaining()
因为write()方法无法保证能写多少字节到SocketChannel,所有重复调用write()知道Buffer中没有要写的字节位置
write() 方法放在 while 循环中
非阻塞模式下,read()可能在尚未读取到任何数据时就返回了,所以需要关注它的int返回值,表示读取了多少字节
使用(以SocketChannel为例)
Channel(通道)
可以把 Buffer 简单的理解成一组基本数据类型的数组
缓冲区数组的总长度
capacity
下一个要操作的数据元素的位置
position
limit <= capacity
缓冲区数组中不可操作的下一个元素的位置
limit
默认是 -1
记录当前 position 的前一个位置
mark
通过几个变量来保存这个数据的当前位置状态
fileChannel.read(buf)
从 Channel 写到 Buffer
buf.put()
通过 Buffer 的 put() 方法
向 Buffer 中写数据
channel.write(buf)
从 Buffer 读取到 Channel
buf.get()
通过 Buffer 的 get() 方法
从 Buffer 中读数据
MappedByteBuffer
HeapByteBuffer
DirectByteBuffer
七种数据类型 Buffer(ByteBuffer等)
ByteBuffer buf = ByteBuffer.allocate(1024)
1. 分配空间
int bytesRead = fileChannel.read(buf)
2. 写入数据到 buffer
position回0
limit 设置为之前 position 的值
3. 调用 flip() 方法
4. 从 Buffer 中读取数据
limit = capacity
清空缓冲区,未读数据将被遗忘
clear()
将未读数据拷贝到 Buffer 起始处
position = 未读数据的位置 + 1
Buffer 可以重新写入数据,但不会覆盖未读数据
compact()
5. 调用 clear() 或 compact()
可以标记 Buffer 中的一个特定的 position
之后可以通过调用 reset() 方法恢复到这个 position
mark() 方法
重读 Buffer 中的所有数据
将position回0
表示能从 Buffer 中读取多少个元素
limit 保持不变
rewind() 方法
使用
Buffer(缓冲区)
可能有几千万客户端同时连接到了服务器
但是在任何时刻都只有非常少量的消息
直到至少一个信道可以进行 IO 操作,并指出是哪个信道
这就需要一种方法阻塞等待
考虑一个 IM 服务器
因为一个选择器能够管理多个信道上的 IO 操作
在调用的时刻没有任何客户端需要 IO 操作
0
一组需要 IO 操作的客户端
返回结果有两种
选择器就是一个多路开关选择器
Selector.open()
使用静态工厂方法 open()
1. 创建 Selector 实例
因为它不能切换到非阻塞模式
FileChannel 不能和 Selector 一起使用
套接字 Channel 都可以
Channel 必须处于非阻塞模式
Connect
Accept
Read
Write
表示 Selector 对监听的 Channel 的什么事件感兴趣
accept中的第二个参数是 Selector 的兴趣点
2. 将想要监控的信道(channel)注册(register)到 Selector 上
返回可进行 IO 操作的信道数量
如果经过一段时间后,仍然没有信道准备好,返回0
int select(long timeout) 可以设置超时时间
没有就返回0
selectNow() 不会阻塞
该方法会阻塞等待,直到有一个或更多的信道准备好了 IO 操作或等待超时
select() 阻塞等待
3. 调用 select() 方法
就绪的 SelectionKey 的集合
必须手动移除
下次就绪时,Selector 会再次将其放入已选择键集中
迭代完成后调用 key 的 remove() 方法,将其从迭代器移除
4. 调用 selectKeys() 方法
register() 方法返回
Selector 的兴趣点
可以通过 SelectionKey 读写 interest 集合
interest 集合
通道已经准备 IO 操作的集合
ready 集合
如 ServerSocketChannel 或 SocketChannel 等
需要转型成需要处理的类型
selectionKey.channel()
Channel
selectionKey.selector()
Selector
selectionKey.attach(Object)
附加的对象(可选)
包含
SelectionKey
Selector(选择器)
三大核心部分
处理超大文件,采用 MappedByteBuffer
读写性能极高
将文件直接映射到内存(虚拟内存)
MappedByteBuffer 是 NIO 引入的文件内存映射方案
实现了对异步操作的支持
说明
可以把文件的从 position 开始的 size 大小的区域映射为内存映像文件
尝试写入抛出 ReadOnlyBufferException
只读
READ_ONLY
对缓冲区的更改最终将传播到文件
该更改对映射到同一文件的其他程序不一定是可见的
READ_WRITE
对缓冲区的更改不传播到文件
其他程序不可见
创建缓冲区已修改部分的专用副本
PRIVATE
mode 指出可访问该内存映像文件的方式
提供了 map() 方法来把文件映射为内存映像文件
在 READ_WRITE 模式下,对缓冲区内容的修改强行写入文件
force()
将缓冲区的内容载入内存,并返回该缓冲区的引用
load()
如果在物理内存中,返回 true
isLoaded()
扩充了三个方法
是 ByteBuffer 的子类
被 MappedByteBuffer 打开的文件只是在GC时才会被关闭
有资源释放的问题
内存映射文件
Java NIO
0 条评论
回复 删除
下一页