NIO基本介绍
- 全称:java-non-blocking IO,同步非阻塞
- java.nio包下
- 三大核心部分:channel(通道)、Buffer(缓冲区)、Selector(选择器)
- NIO是面向缓冲区、或者面向块编程的,数据读取到一个它稍后处理的缓冲区,需要使可以在缓冲区中前后移动,增加灵活性,使用它可以提供非阻塞式的高伸缩性网络
- Java NIO 的非阻塞模式,使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
BIO 与 NIO的区别
- BIO以流的方式处理数据,NIO以块的方式处理数据,块IO的效率比流IO的效率高很多
- BIO是阻塞的,NIO是非阻塞的
- BIO基于字节流和字符流进行操作,而NIO是基于channel(管道)和Buffer(缓冲区进行操作),数据总是从 通道读取到缓冲区,或者从缓冲区写入到通道(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道
Buffer的基本使用
- 读 写
- 方法IntBuffer. allocate(int )
- put存入
- flip(读写切换)
public static void main(String[] args) {
// 举例说明Buffer的使用
// 创建一个Buffer,里面可以存放5个int
IntBuffer intBuffer = IntBuffer.allocate(5);
// 向buffer中存放数据
for (int i = 0; i < intBuffer.capacity(); i++) {
intBuffer.put(i*2);
}
// 从buffer 中读取数据
// 将buffer转换,读写切换
intBuffer.flip();
while(intBuffer.hasRemaining()) {
System.out.println(intBuffer.get());
}
}
NIO中Selector、Channel、Buffer关系图
三个Channel注册到一个selector
- 每个Channel都会对应一个Buffer
- Selector对应一个线程,一个线程对应多个Channel(连接)
- 程序切换到哪儿个Channel是由事件决定,Event是一个重要的事件概念
- Selector会根据不同的事件,在各个管道间进行切换
- Buffers一个内存快,底层是一个数组
- 数据的读写是通过Buffer,它是双向的可读可写,需要通过flip方法进行切换,与BIO中输入流或者输出流只能是单向的不同; Channel是双向的,可以返回底层操作系统情况,比如linux,底层的操作系统通道就是双向的
Buffer缓冲区的介绍
缓冲区(Buffer),本质是一个可以读写数据的内存块,可以理解成一个容器对象(含数组),该对象提供一组方法,可更轻松地使用内存块,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。Channel提供从文件、网络读取数据的渠道,但是读取或写入的数据必须经过Buffer ,如图所示
Buffer及其子类
Buffer缓冲区的四个属性(重要)
源码
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
属性 | 描述 |
---|---|
capacity | 容量,缓冲区可以容纳最大的数据量;在缓冲区创建时被设定,不能改变 |
limit | 表示当前终点,不能对超过limit的位置进行操作,且极限可以修改 |
position | 位置,下一个要读写的元素索引,每次读写都会改变 |
mark | 标记 |