首页 > 代码库 > Java - NIO

Java - NIO

NIO

 面向流的IO体系一次只能处理一个字节/字符,效率低,且在数据源中没有数据时会阻塞线程。Java-4提供的新API,Non-blocking IO(New IO,面向块的IO体系)为所有的原始类型提供Buffer缓存支持。采用内存映射文件的方式处理输入输出,将文件或文件的一段区域映射到内存中,模拟OS中虚拟内存的概念,提高IO速度。

区别

  • IO:阻塞式IO,面向流、基于字节/字符流;
  • NIO:非阻塞式IO,面向块(缓冲区)、基于通道/缓冲区,选择器;

Sun官方标榜的特性

  • 为所有的原始类型提供缓存(Buffer)支持;
  • Java.nio.charset:字符集编码解码解决方案;
  • Channel:一个新的原始I/O抽象;
  • 支持锁和内存映射文件的文件访问接口;
  • 提供多路非阻塞式(non-bloking)的高伸缩性网络I/O;

思路:分而治之、专人入则专门的任务,多路复用IO,解决处理速度的差异,避免阻塞带来的多进/线程间的上下文切换。

工作原理

  • 由一个专门的线程来处理所有的IO事件并负责分发;
  • 事件驱动机制:事件到达时触发而不是同步的去监视事件;
  • 线程通讯:线程之间通过wait、notify等方式通讯,保证每次上下文切换都是有意义的、减少无谓的线程切换;

NIO的核心的API:ChannelBufferSelector

Channel 

 通道,对传统IO系统的模拟,传输数据,但是双向的、可读可写,支持异步I/O。Channel对象通过IO流对象的getChannel()方法获得。其map()方法将“一块数据”映射到内存中。

  • FileChannel:读写文件;
  • SocketChanel:通过TCP向网络连接的两端读写数据;
  • ServerSocketChannel:能够监听客户端发起的TCP连接并为每个TCP连接创建一个新的SocketChannel用于数据读写;
  • DatagramChannel:以UDP向网络连接的两端读写数据;

Buffer

 缓冲区,连续内存块、本质是数组,支持多种数据类型,数据读写中转站。顶层父类、抽象类,最常用的是ByteBuffer。一个buffer主要由position、limit、capacity三个变量控制读写过程:

  • position:当前读取的单位数据位置/当前写入的单位数据数量;
  • limit:最多能读多少单位数据,和之前写入的单位数据量一致/最多能写多少单位数据,和容量一致;
  • capacity:buffer容量;

函数

  • clear():清空buffer(position=0,limit=capacity)
  • flip():将写模式转换为读模式(重置position、limit参数),准备将buffer中的数据读出并写到channel中
  • rewind():position重置为0,用于重复读
  • mark() + reset():标记位置 + 复位到该位置
  • compact():将未读取的数据拷贝到buffer的头部位(清除已读数据)

步骤

  1. 将数据写入到Buffer
  2. 调用flip()方法
  3. 从Buffer中读取数据
  4. 调用clear()方法或compact()方法

内存映射文件I/O

 一种读和写文件数据的方法,将文件中实际读取或写入的数据映射到内存中,速度更快。

 MappedByteBuffer类,继承于ByteBuffer类。

Selector

 选择器,支持NIO非阻塞式、基于Reactor模式的工作方式,实现非阻塞I/O的核心对象是Selector。允许单线程监听和处理多个Channel的事件。通过注册Channel事件到Selector,再调用方法select()获取到达的事件并对事件响应处理。

SelectionKey

 一个SelectionKey表示一个到达事件,包含事件的状态信息以及对应的通道的绑定。

 

参考

  • Java NIO:NIO概述; Java NIO原理分析;
  • 一个故事讲清楚NIO;
  • Java NIO:迟迟登场的NIO;
  • Java NIO 系列教程;

 

Java - NIO