NIO介绍
- 全程java non-blocking IO,是JDK提供的新API。从1.4开始,提供了一系列改进的输入、输出特性,被统称为NIO,即同步非阻塞
- NIO相关类放到了java.nio下,并且对原java.io包中的很多了进行了改写
- NIO三大组件:Channel,Buffer,Selector
- NIO是面向缓冲区,或者面向块的编程。增加了处理的灵活性,实现了同步通信的非阻塞
NIO和BIO的比较
- BIO以流的方式处理数据,NIO以块的方式处理数据,块IO的效率高很多
- BIO是阻塞的,NIO是非阻塞的,但都是同步的
- BIO基于字节流和字符流操作,而NIO基于Channel和Buffer操作,数据总是从通道读取到缓冲区,或从缓冲区写入到通道。Selector用来监听多个通道的事件(连接请求、数据到达等),因此使用单个线程就可以监听多用户通道
NIO三大核心原理示意图
- 每个channel对应一个buffer
- selector对应一个线程,一个线程对应多个channel,channel注册到selector
- 程序切换到哪个channel是事件决定
- selector会根据不同事件,在各个channel上切换
- buffer就是一个内存块,底层是数组
- NIO数据的读取写入通过buffer,读取的切换通过flip方法,而BIO是直接操作输入、输出两种流
- channel是双向的,可以返回底层操作系统的情况,比如linux,底层的操作系统通道就是双向的,即全双工
Buffer
Buffer介绍
缓冲区本质是一个可以读写数据的内存块,可以理解为一个数组容器对象,该对象提供了方法来管理缓冲区,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化。Channel提供从文件、网络读取数据的渠道,但是读取或写入的数据必须经由Buffer
Buffer类
Buffer子类
Buffer类定义了所有的缓冲区都具有的四个属性来提供关于其包含的数据元素
属性 | 描述 |
---|---|
capacity | 私有,表示当前Buffer的容量,创建后不可变 |
limit | 私有,表示读写的最大值,<=capacity |
position | 私有,索引位,初始值0 |
mark | 私有,标记,初始值-1 |
Buffer读写的属性变化图示
上手验证
debug代码观察上述属性的变化
java
public class BasicBuffer {
public static void main(String[] args) {
// 创建一个大小为5个int值的buffer
IntBuffer intBuffer = IntBuffer.allocate(5);
for(int i=0;i<intBuffer.capacity();i++){
intBuffer.put(i*2);
}
// 如何从buffer读取数据
// 将buffer转换,读写切换
intBuffer.flip();
while(intBuffer.hasRemaining()){
System.out.println(intBuffer.get());
}
}
}
相关方法
方法 | 功能 |
---|---|
public final int capacity() | 获取buffer容量 |
public final int position() | 获取索引位置 |
public final Buffer position(int newPosition) | 设置缓冲区的位置 |
public final int limit() | 返回此buffer的限制 |
public final Buffer limit(int newLimit) | 设置缓冲区的限制 |
public final Buffer mark() | 在缓冲区的位置设置标记 |
public final Buffer reset() | 将缓冲区的位置重置为mark的值 |
public final Buffer clear() | 清除缓冲区,将各个标记恢复到初始态,数据并未清除 |
public final Buffer flip() | 读写切换 |
public final Buffer rewind() | 重绕此缓冲区 |
public final int remaining() | 返回当前位置和限制之间的元素数 |
public final boolean hasRemaining() | 告知缓冲区当前位置和限制之间是否有元素 |
public abstract boolean isReadOnly() | 是否为只读缓冲区 |
public abstract boolean hasArray() | 告知缓冲区是否具有可访问的底层实现数组 |
public abstract Object array() | 返回此缓冲区的底层实现数组 |
public abstract int arrayOffset() | 返回此缓冲区的底层实现数组中第一个缓冲区元素的偏移量 |
public abstract boolean isDirect() | 告知此缓冲区是否为直接缓冲区 |