概述
JAVA NIO是IO复用模型( POSIX定义的五种IO模型: 阻塞IO, 非阻塞IO, IO复用, 异步IO, 信号驱动IO )的实现.
在Linux系统中,复用IO用三种实现: select, poll, epoll.
select
select实现有2个问题,文件描述符的限制以及需要对所有监听的channel进行遍历
poll
poll实现解决的是描述符限制, 依然还需要进行channel遍历
epoll
epoll解决了遍历channel的问题, 通过向内核注册事件, 当有监听事件发生时, 可以准确知道是哪个channel
复用IO本质上还是阻塞的, 内核读取到数据后, 用户进程从内核进程中拷贝数据的过程是同步阻塞的. IO模型中的异步I是完全异步的, 内核会将数据拷贝到用户进程后, 才会通知用户进程.
Selector
Java文档中描述Selector:
A multiplexor of SelectableChannel objects.
可以理解为SelectableChannel对象的多路复用实现.Channel(SelectableChannel)可以通过Selector实现多路复用.
java.nio中定义了一个Selector类,可以通过其open()静态方法获取Selector实例.
还有另外一种机制是通过SelectorProvider自定义实现获取selector, SelectorProvider是通过SPI机制动态发现其实现类.
Buffer
Buffer是一个数据缓冲区, 属于堆外内存, 不属于在JVM运行时内存模型.
Java文档中描述Buffer:
A container for data of a specific primitive type.
可以理解为基本类型数据的容器。
在输入的时候, Buffer是Channel的输入源, 在输出的时候, Buffer是输出源.
java.nio中实现多种基本类型的Buffer(ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer)
.
当类型是ByteBuffer的时候, 要注意编码的问题.
Channel
Java文档中对Channel的描述是:
A nexus for I/O operations.
可以理解为 IO操作的一个纽带.
java.nio.channels.SelectableChannel
定义了Channel可以通过selector实现多路复用.
DatagramChannel, Pipe.SinkChannel, Pipe.SourceChannel, ServerSocketChannel, SocketChannel
这几个类是其子类(实际是AbstractSelectableChannel的直接子类),也就是说这几个类型的channel可以实现多路复用.然而FileChannel不在其中, 也就是磁盘IO不能实现多路复用.
那么问题来了, FileChannel为什么不能实现多路复用?既然不能实现IO复用, 为何又要提供一个FileChannel的类呢?