NIO

简述

三大核心组件:通道(channel),缓冲区(buffer),选择器(selector)

传统IO针对字节流或字符流进行操作,NIO基于channel和buffer进行操作,数据从通道channel读取到缓冲区buffer,或从缓冲区buffer写入到通道channel中。Selector用于监听多个通道的事件(打开连接,数据就绪),因此单个线程可以监听多个通道。

与IO的区别

IO                 NIO

面向流      面向缓冲区

阻塞        非阻塞

--            选择器

通道(Channel)

 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。

通道可以异步地读写。

通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

channel的实现

FileChannel:从文件中读写数据。

DatagramChannel:能通过UDP读写网络中的数据。

SocketChannel:能通过TCP读写网络中的数据。

ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

缓冲区(Buffer)

常见类型:MappedByteBuffer  CharBuffer  DoubleBuffer  FloatBuffer  IntBuffer  LongBuffer  ShortBuffer

读写步骤:

1.写入数据到Buffer(记录写入多少数据)

2.调用flip()方法(开始读取,模式切换。写--读)

3.从Buffer中读取数据

4.调用clear()方法或者compact()方法(清空缓冲区)

NIO_第1张图片

Buffer重要属性:

capacity:作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

position:写数据时,表示当前位置,初始值=0,最大值为capacity-1;当数据写入到buffer时,position会向前移动到可插入数据的buffer区;

读取数据时,也是从某个特定位置读取。当buffer从写切换到读模式下,position会重置为0,当从buffer的position处读取数据时,position会向前移动到下一个可读位置。

limit:写模式下,表示最多能往buffer离写多少数据,limit等于buffer的capacity的大小。

   读模式下,表示你最多能去取到的数据。当切换buffer到读模式时,limit==写模式下的position。

NIO_第2张图片

分散(Scatter):从channel中读取操作时将数据写入到多个buffer中

聚集(Gather):写入操作时,将多个buffer中的数据聚集后发送到同一个channel中。

选择器(Selector)

是NIO中能够检测到一到多个通道,并且知道通道是否为类似读写事件做好准备的组件。  允许单线程处理多个通道

为了将Channel和Selector配合使用,必须将channel注册到selector上。通过SelectableChannel.register()方法实现。一起使用适合,channel必须处于非阻塞模式下,FileChannel不能切换到非阻塞模式,套接字通道都可以。 

1、connect:客户端连接服务端事件,对应值为SelectionKey.OP_CONNECT

2、accept:服务端接收客户端连接事件,对应值为SelectionKey.OP_ACCEPT

3、read:读事件,对应值为SelectionKey.OP_READ

4、write:写事件,对应值为SelectionKey.OP_WRITE

当向Selector注册Channel时,register()方法会返回一个SelectionKey对象,该对象有以下属性:

interest集合:通过SelectionKey可以读写到该集合

ready集合:通道已经准备就绪的操作的集合。在一次选择(Selection)之后,你会首先访问这个ready set

Channel

Selector

附加的对象(可选)

通过Selector选择通道,可调用重载的select()方法:返回读事件已经就绪的 通道,返回的int值表示通道就绪数

int select():阻塞到至少有一个通道在你注册的事件上就绪了。

int select(long timeout):和select()一样,除了最长会阻塞timeout毫秒(参数)

int selectNow():不会阻塞,不管什么通道就绪都立刻返回

一旦调用select()方法,且返回值表明了有就绪通道,可通过selectedKeys()方法访问已选择的就绪通道。Set selectedKeys = selector.selectedKeys();  

wakeUp() :处理阻塞在select()上的线程

close() :用完Selector后调用其close()方法会关闭该Selector,且使注册到该Selector上的所有SelectionKey实例无效。通道本身并不会关闭。

你可能感兴趣的:(NIO)