NIO
bio的面向流的io,它建立的通道都是单向的,所以输入和输出流的通道不相同,必须建立2个通道,通道内都是传输的字节数组
nio中,不再是面向流的io了,而是面向缓冲区,它会建立一个通道(Channel),而通道上会有一个缓冲区(Buffer)用于存储真正的数据
通道只是作为运输数据的一个连接资源,而真正存储数据的是缓冲区。即通道负责传输,缓冲区负责存储
BIO | NIO |
---|---|
面向流(Stream) | 面向缓冲区(Buffer) |
单向通道 | 双向通道 |
阻塞IO | 非阻塞IO |
选择器(Selectors) |
缓冲区(Buffer)
缓冲区是存储数据的区域,在java中,缓冲区就是数组,为了可以操作不同数据类型的数据,java提供了许多不同类型的缓冲区,除了布尔类型以外,其它基本类型都用对应的缓冲区数组对象
为什么没有布尔类型的缓冲区?
在java中,boolean类型数据只占用1bit,而在io传输过程中,都是以字节为单位进行传输的,所以boolean的1bit完全可以使用byte类型的某一位,或者int类型的某一位表示,没必要为了这1bit而专门提供一个缓冲区
缓冲区 | 存储类型 |
---|---|
ByteBuffer | 字节 |
CharBuffer | 字符 |
ShortBuffer | 短整型 |
IntBuffer | 整形 |
LongBuffer | 长整型 |
FloatBuffer | 单精度浮点型 |
DoubleBuffer | 双精度浮点型 |
分配一个缓冲区
- allocate()
读写数据
- put():将数据写入到缓冲区中
- get():从缓冲区读取数据
重要属性
- capacity:缓冲区中最大存储数据的容量,一旦声明则无法改变
- limit:表示缓冲区可以操作数据的大小,limit之后的数据无法进行读写。必须满足limit<=capacity
- position:当前缓冲区正在操作数据的下标位置,必须满足position<=limit
- mark:标记位置,调用reset()将position位置调整到mark属性指向的下标位置,实现多次读取数据
辅助方法
- flip():可以实现读写模式切换,会将limit设置为当前写的位置,position设置为0,即从头开始读取
- rewind():可以将position位置设置为0,再次读取缓冲区中的数据
- clear():情况整个缓冲区,它会将position设置为0,limit设置为capacity,可以写整个缓冲区
通道(Channel)
通道作为一种连接资源,作用是传输数据,而真正存储数据的是缓冲区
通道是可以双向读写的,传统bio需要使用输入\输出流表示数据的流向,zainio中可以减少通道资源的消耗
通道类
io通道类型 | 具体类 |
---|---|
文件io | FileChannel(用于文件读写) |
tcp网络io | SocketChannel(用于读写数据的tcp通道) ServerSocketChannel(监听客户端的连接) |
udp网络io | DatagramChannel(收发udp数据报的通道) |
获取通道
可以通过getChannel()方法获取一个通道
- 文件io:FileInputStream、FileOutputStream、RandomAccessFile
- tcp网络:Socket、ServerSocket
- udp网络:DatagramSocket
选择器(Selectors)
底层利用了多路复用io机制,让选择器可以监听多个io连接,根据io的状态响应到服务器端进行处理
选择器可以连接监听多个io连接,而传统的bio每个io连接都需要有一个线程去监听和处理
在java nio中,选择器使用Selector类表示,Selector可以接收各种io连接,在io状态准备就绪时,会通通知通道注册的Selector,Selector在下一次轮询时会发现该io连接就绪,进而处理该连接
基本结构
重要方法 | 方法解析 |
---|---|
open() | 打开一个Selector选择器 |
select() | 阻塞的等待就绪的通道 |
select(long timeout) | 最多阻塞timeout毫秒,如果是0则一直阻塞等待 |
selectNow() | 非阻塞的轮询就绪的通道 |
如果用户进程轮询时没有发现就绪的通道
- 一直等待直到一个就绪的通道,再返回给用户进程
- 立刻返回一个错误状态码给用户进程,让用户进程继续运行,不会阻塞
选择键
在选择器轮询到就绪通道时会返回这些通道的就绪选择键,通过选择键可以获取到通道进行操作
- SelectionKey.OP_READ:套接字通道准备好进行读操作
- SelectionKey.OP_WRITE:套接字通道准备好进行写操作
- SelectionKey.OP_ACCEPT:服务器套接字通道接收其它通道
- SelectionKey.OP_CONNECT:套接字通道准备完成连接
SelectionKey的属性
- channel:该选择键绑定的通道
- selector:轮询到该选择键的选择器
- readyOps:当前就绪选择键的值
- InteresOps:该选择器对该通道感兴趣的所有选择器