Java NIO提供了与标准IO不同的IO工作方式。
Channels and Buffers(通道和缓冲区)
标准IO基于字节流和字符流,NIO基于通道(Channel)和缓冲区(Buffer)。数据从channel读取到buffer,或从Buffer写入到Channel
一些主要Channel的实现
- FileChannel 从文件中读写数据
- DatagramChannel 通过UDP读写网络中数据
- SocketChannel 通过TCP读写网络中数据
- ServerSocketChannel 监听进来的TCP连接,类似web服务器。每个新来的连接创建一个SocketChannel
示例:
Buffer的三个属性:capacity、position、limit
Buffer有如下几个类型:
- ByteBuffer
- MappedByteBuffer 比较特别
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
Scattering Reads(Channel分散写入多个Buffer)
Gathering Writers(多个Buffer写入同一个Channel)
sactter/gather 经常用于需要将传输的数据分开处理的场合;如传输一个由消息头和消息体组成的信息,可以将消息体和消息头分散到不同的Buffer中,这样可以方便的处理消息头和消息体。
Non-blocking IO
java NIO可以非阻塞的使用IO;当线程从某channel进行读写数据时,若没有数据可用,该线程可进行其他任务。线程通常将非阻塞IO的空闲时间用于其他通道执行IO操作,所以单独的线程可管理多个输入和输出channel
Selectors(选择器)
NIO引入了选择器的概念,用于检查一个或多个Channel是否处于可读、可写。如此可实现单线程管理多个Channel,也就可用管理多个网络连接。
register()函数的第二个参数,是一个interest集合,代表Selector监听Channel时对什么事件感兴趣,有4种事件:
- SelectionKey.OP_ACCEPT
接收连接就绪,代表Selector监听到了Channel,可以接收这个Channel了 - SelectionKey.OP_CONNECT
连接就绪,代表Channel与Selector之间的连接已经成功建立 - SelectionKey.OP_READ
读就绪,代表Channel中已有数据,可以进行读操作了 - SelectionKey.OP_WRITE
写就绪,代表可以向Channel写数据了
SocketChannel(连接到TCP网络套接字的通道)
两种方式创建SocketChannel:
- 打开一个SocketChannel并连接到互联网上的某台机器
- 一个新连接到达ServerSocketChannel时,会创建一个SocketChannel
ServerSocketChannel
Pipe(管道)
Java NIO 管道是2个线程之间的单向数据连接,Pipe有一个source和sink通道。数据会被写到sink通道,从source读取。
IO与NIO区别
- 面向流与面向缓冲:
IO面向流意味着每次 从流中读字节,它们没有被缓存到任何地方。NIO有缓冲区,增加了处理过程中的灵活性 - 阻塞与非阻塞IO:
IO是阻塞的,意味着当一个线程read()或write()时,该线程被阻塞,不能做别的事。NIO的非阻塞模式,一个线程从某通道 发送请求读取数据,如果当前没有数据可获取,直至数据变的可以读取前,该线程可以做其他事。 - Selector(选择器)