概述:
JDK1.4引入的一种IO模式,是一种非阻塞的,面向缓冲区,基于通道的一种IO,以Channel( 通道) ,Buffer( 缓冲区), Selector( 选择器) 为核心
和传统IO(BIO)的对比:
先上图
观察上图,我们可以看出,传统的IO呢,他完全是基于流的方式在处理数据,就好比一根管子,比如我们拿吸管喝可乐,你要么就是吸,要么就是往你可乐杯子里面吐,不能做其他的,是一种单向的操作,你现在在吐,但是你想吸的话,你必须等你吐完了才能吸,你一时间只能做一件事。
而观察第二幅图,就比第一幅图丰富多了,对比第一幅图BIO,你可以观察到服务端面向多个客户端是用了3条线程,第二幅图咋一看也是,实际上不是的,NIO面对3个客户端只创建了一条线程,为什么这样呢?其中不得不说他的一些概念,它不像传统IO直接和流进行交互,它是和selector(选择器)交互,然后selector通过监听channel(管道),channel基于buffer(缓冲区)配合来进行读写数据(BIO是单向的,要么写要么读,NIO是双向的),这里多少说得有点粗糙,下面进行一一说明。
Buffer(缓冲区):
上图说明:
蓝色边白色的空心代表Channel(管道),中间的一块区域是Buffer(缓冲区),这个图我觉得我表达出了Channel是一个端到端交互的一个连接,本质上还是一个流,但是这个流不是和传统的流一样,单个管道的,而是通过流入Buffer里面,进行缓存,两端再根据需要是读取还是写入,反正都会先经过管道再经过缓存,形成了一个管道,两种功效(读写可同时进行)
Buffer类似于数组,有多种类型:
- ByteBuffer
- CharBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
buffer的属性和api
- public static ByteBuffer allocate(int capacity)
给buffer分配一个容量为 capacity 的空间 - public final int position();
数组的当前位置,刚初始化buffer的时候,这个值为0,代表着下一次要操作元素的位置是0,也就是第一位,如果加入4个字节,那么在这个数组没有归位之前,我们数组前4为就被占住了,那么当前position也就是我们下次能操作的位置也就是4(0,1,2,3被占住) - public final int limit();
可以理解为存有数据的界限吧,缓冲区数组中不可操作的下一个元素的位置
Buffer clear() 清空缓冲区并返回对缓冲区的引用
Buffer flip() 为 将缓冲区的界限设置为当前位置,并将当前位置充值为 0
int capacity() 返回 Buffer 的 capacity 大小
boolean hasRemaining() 判断缓冲区中是否还有元素
int limit() 返回 Buffer 的界限(limit) 的位置
Buffer limit(int n) 将设置缓冲区界限为 n, 并返回一个具有新 limit 的缓冲区对象
Buffer mark() 对缓冲区设置标记
int position() 返回缓冲区的当前位置 position
Buffer position(int n) 将设置缓冲区的当前位置为 n , 并返回修改后的 Buffer 对象
int remaining() 返回 position 和 limit 之间的元素个数
Buffer reset() 将位置 position 转到以前设置的 mark 所在的位置
Buffer rewind() 将位置设为为 0, 取消设置的 mark
可以写点demo,往里面加数据,观察buffer的变化,直接输出buffer可以看到里面对应的一些属性,它重写了toString()的,这里不多赘述,不知咋讲,又浪费时间。
【补充】
我们上面用的ByteBuffer.allocate(num);是 非直接缓存 ,还有一种ByteBuffer.allocateDirect(num) 是属于 直接缓存 ,适用于并发场景下和大数据存储下。
Channel:
可以理解为:可以异步读写和buffer交流的双向流
分类:
- FileChannel:用于读取、写入、映射和操作文件的通道。
- DatagramChannel:通过 UDP 读写网络中的数据通道。
- SocketChannel:通过 TCP 读写网络中的数据。
- ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。 【ServerSocketChannel 类似 ServerSocket , SocketChannel 类似 Socket】
其实有很多例子的,就是demo,我觉得说起来太费劲了,我就不说了,主要是这个帖子写来就是我复习用的,不太适合别人阅读吧!
Selector
- Java 的 NIO,用非阻塞的 IO 方式。可以用一个线程,处理多个的客户端连接,就会使用到 Selector(选择器)
- Selector 能够检测多个注册的通道上是否有事件发生(注意:多个 Channel 以事件的方式可以注册到同一个
Selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管
理多个通道,也就是管理多个连接和请求。