一、什么是NIO? 与BIO有哪些区别?
1.什么是NIO?
1、NIO = Selector+Channel+Buffer=构建Reactor模型。
2、非阻塞IO,对应的IO模型是 多路复用IO。
NIO: 同步非阻塞式IO,服务器实现模式为多个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
NIO 是一种同步非阻塞的 IO 模型。
1)同步是指线程(多路复用器)不断轮询 IO 事件是否就绪,非阻塞是指线程在等待 IO 的时候,可以同时做其他任务。
2)同步的核心就是 Selector,Selector 代替了线程本身轮询 IO 事件,避免了阻塞同时减少了不必要的线程消耗;
3)非阻塞的核心就是通道和缓冲区,当 IO 事件就绪时,可以通过写道缓冲区,保证 IO 的成功,而无需线程阻塞式地等待。
3、NIO = BUFFER + Selector + Channel
4、非阻塞= BUFFER + Channel;
5、同步= Selector ;
2.NIO和BIO的区别?
1.OIO面向流(字节/字符),NIO面向缓冲区。流:要求顺序,缓冲区不必、
2.OIO是阻塞的
3.OIO没有选择器,NIO有。
NIO《-》OIO
Channel《-》Socket
ServerChanel《-》ServerSocket
BIO(accept、io 都是阻塞):同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
二、NIO的基本组成:
1.Channel:通道,互相通信的入口。
2.Buffer:缓冲器,数据临时保存的地方。
3.Selector:多路复用器,由系统提供,实现一个线程能够轮训多个通道的核心。
1、Channel:
FileChannel : 文件
DatagramChanne : UDP
SocketChannel : 与客户端建立产生的socket
ServerSocketChannel : 服务端socket
(1)FileChannel文件通道,用于文件的数据读写。
//文件拷贝
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try {
//从inChannel文件中读出count bytes ,并写入outChannel文件。
inChannel.transferTo(0, inChannel.size(), outChannel);
} finally {
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
(2)SocketChannel套接字通道,用于Socket套接字TCP连接的数据读写。
(3)ServerSocketChannel服务器嵌套字通道(或服务器监听通道),允许我们监听TCP连接请求,为每个监听到的请求,创建一个SocketChannel套接字通道。、
(4)DatagramChannel数据报通道,用于UDP协议的数据读写。
2、BUFFER 缓冲器:
BUFFER = 为什么说NIO是基于缓冲区的IO方式呢?因为,当一个链接建立完成后,IO的数据未必会马上到达,为了当数据到达时能够正确完成IO操作,在BIO(阻塞IO)中,等待IO的线程必须被阻塞,以全天候地执行IO操作。为了解决这种IO方式低效的问题,引入了缓冲区的概念,当数据到达时,可以预先被写入缓冲区,再由缓冲区交给线程,因此线程无需阻塞地等待IO。
在 JDK 1. 4 中 新 加入 了 NIO( New Input/ Output) 类, 引入了一种基于通道和缓冲区的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆的 DirectByteBuffer 对象作为这块内存的引用进行操作,避免了在 Java 堆和 Native 堆中来回复制数据。
2.1、通道的读取:就是将数据从通道读取到缓冲区中;通道的写入,就是将数据从缓冲区中写入到通道中。
NIO的Buffer(缓冲区)本质上是一个内存块,既可以写入数据,也可以从中读取数据。
NIO的Buffer类,是一个抽象类,位于java.nio包中,其内部是一个内存块(数组)。
NIO的Buffer与普通的内存块(Java数组)不同的是:NIO Buffer对象,提供了一组更加有效的方法,用来进行写入和读取的交替访问。
需要强调的是:Buffer类是一个非线程安全类。
2.2、Buffer的属性:
位置(position):当前缓冲区(Buffer)的位置,将从该位置往后读或写数据。
容量(capacity):缓冲区的总容量上限。
上限(limit):缓冲区的实际容量大小。
2.3、Buffer的分类:(除Boolean)
ByteBuffer、
CharBuffer、
DoubleBuffer、
FloatBuffer、
IntBuffer、
LongBuffer、
ShortBuffer、
MappedByteBuffer
2.4、Buffer的原理:
默认初始:写模式:position=0,limit=capacity
1.在写入模式下,position的值变化规则如下:
(1)在刚进入到写模式时,position值为0,表示当前的写入位置为从头开始。
(2)每当一个数据写到缓冲区之后,position会向后移动到下一个可写的位置。
(3)初始的position值为0,最大可写值position为limit-1。当position值达到limit时,缓冲区就已经无空间可写了。
2.flip()翻转后limit=position,position=0
3.在读模式下,position的值变化规则如下:
(1)当缓冲区刚开始进入到读模式时,position会被重置为0。
(2)当从缓冲区读取时,也是从position位置开始读。读取数据后,position向前移动到下一个可读的位置。
(3)position最大的值为最大可读上限limit,当position达到limit时,表明缓冲区已经无数据可读。
数据写入后,如果要从缓冲区读取数据,这就要进行模式的切换,可以使用(即调用)flip翻转方法,将缓冲区变成读取模式。
3、Selector多路复用器:
依赖底层的epoll/select , JavaSelector选择器可以监听多个文件描述符(一个网络连接系统底层使用一个文件描述符表示),实现IO多路复用。
实现IO多路复用,从具体的开发层面来说,首先把通道注册到选择器中,然后通过选择器内部的机制,可以查询(select)这些注册的通道是否有已经就绪的IO事件(例如可读、可写、网络连接完成等)。
三、NIO的编程模板:
1、NIO编程服务端时序图:
2、NIO编程服务端步骤:
网友评论