IO流和NIO流
基本区别: 传统IO是面向流的,NIO是面向缓冲的。传统IO是每次从流中读一个或多个字节,直到读取所有字节,它们没有被缓存在任何地方。 NIO是将数据读取到一个稍后处理的缓冲区,需要时可在缓冲区中前后移动,增加了处理过程中的灵活性。 IO与NIO的适用场景: 如果需要管理同时打开的成千上万个连接,这些连接每次只是发送少量的数据,例如聊天服务器,实现NIO的服务器可能是一个优势。 如果你有少量的连接使用非常高的带宽,一次发送大量的数据,也许典型的IO服务器实现可能非常契合。 底层处理: IO流是每次处理一个或多个字节。 NIO流是以数据块为单位来处理,缓冲区就是用于读写的数据块。
NIO介绍
nio核心
NIO 有三大核心部分:Channel(通道),Buffer(缓冲区), Selector(选择器) 。 Channel和Buffer:NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。 Selector:选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
nio面向"块"
NIO是 面向缓冲区 ,或者面向 块 编程的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络 (数据读取到缓冲区后可以前后移动的意思:详细理解下面缓冲区的参数说明和常用方法即可)
nio的非阻塞
Java NIO的非阻塞模式,使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。(同步异步阻塞非阻塞概念链接: link.) 举例:NIO是可以做到用一个线程来处理多个操作的。假设有10000个请求过来,根据实际情况,可以分配50或者100个线程来处理。不像之前的阻塞IO那样,非得分配10000个。
NIO流程图
java.nio.ByteBuffer
Buffer参数说明
主要有五个属性:mark,position,limit,capacity和array mark:记录了当前所标记的索引下标; position:对于写入模式,表示当前可写入数据的下标,对于读取模式,表示接下来可以读取的数据的下标; limit:对于写入模式,表示当前可以写入的数组大小,默认为数组的最大长度,对于读取模式,表示当前最多可以读取的数据的位置下标; capacity:表示当前数组的容量大小; array:保存了当前写入的数据。
Buffer的常用方法:
flip():确定缓冲区数据的起始点和终止点,为输出数据做准备(即写入通道)。此时:limit = position,position = 0。 clear():缓冲区初始化,准备再次接收新数据到缓冲区。position = 0,limit = capacity。 remaining():判断postion到limit之间是否还有元素。(查看源码该方法返回的就是 limit - position) rewind():postion设为0,则mark值无效。 limit(int newLt):设置界限值,并返回一个缓冲区,该缓冲区的界限和limit()设置的一样。 get()和put():获取元素和存放元素。使用clear()之后,无法直接使用get()获取元素,需要使用get(int index)根据索引值来获取相应元素。
实例Demo
ByteBuffer respHeader = ByteBuffer.allocate(8);
Socket client = new Socket();
InputStream is = client.getInputStream();
byte[] tmpHeader = new byte[8];
int length = 0;
while ((respHeader.remaining() != 0) && ((length = is.read(tmpHeader)) != -1)) {
respHeader.put(tmpHeader, 0, length);
tmpHeader = new byte[respHeader.remaining()];
}
respHeader.array();
|