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