——简介
Java NIO(New IO——新IO,NON Blocking IO——非阻塞IO),从Java1.4版本开始引入的一个新的IO API,可以代替Java IO API。NIO与原来的IO有同样的作用和目的,但是使用方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
NIO与IO的主要区别
通道和缓冲区
- Java NIO核心:通道(Channel)和缓冲区(Buffer)。通道表示打开到IO设备(例如:文件、套接字)的连接。若需要N使用NIO系统,需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。简而言之:Channel用于传输,Buffer负责存储。
通道:用于源节点和目标节点的连接。在Java NIO中负责缓冲区中数据的传输。Channel本身不存储数据,因此需要配合缓冲区进行传输
- 主要实现类Channel接口:
- FileChannel:本地文件通道
- SocketChannel:网络
- ServerSocketChannel
- DatagramChannel
- 获取通道:
- 本地IO:FileInputStream/FileOutputStream
- 网络IO:Socket、ServerSocket、DatagramSocket
- 针对各个通道提供了静态方法open()
- Files工具类的newByteChannel()
缓冲区:在Java NIO中负责数据的存取。缓冲区就是数组。用于存储不同类型的数据。
- 根据数据类型的不同(boolean除外),提供相应类型的缓冲区:ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer
- 缓冲区管理的方法几乎一致,通过allocate()获取缓冲区
- 两个核心方法:
- put:存入数据到缓冲区内
- get:获取缓冲区的数据
- 其他方法:
- flip:切换成读模式
- rewind:可重复读
- clear:清空缓冲区,但是缓冲区中的数据依旧存在,只是处于一种被遗忘的状态
- 四个核心属性:
- capacity:容量,表示缓冲区中最大存储数据的容量。一旦声明不可改变
- limit:界限,表示缓冲区中可以操作数据的大小。limit后数据不能进行读写
- position:位置,表示缓冲区中正在操作数据的位置
- mark:标记,记录当前position的位置,可以通过reset恢复到mark的位置
- 0<=mark<=position<=limit<=capacity
直接缓冲区和非直接缓冲区
- 非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM内存中
- 直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率。
分散Scatter和聚集Gather
- 分散读取(Scatter Reads):是指从Channel中读取的数据“分散”到多个Buffer中(按照缓冲区的顺序,从Channel中读取的数据依次将Buffer填满)
- 聚集写入(Gather Writes):是指将多个Buffer中的数据“聚集”到Channel(按照缓冲区的顺序,写入position和limit之间的数据到Channel)
字符集Charset
- 编码:字符串 ——》字节数组
- 解码:字节数组——》字符串
——阻塞和非阻塞
使用NIO完成通信的三个核心
- 通道(Channel):负责连接
- java.nio.Channels.Channel接口
- SelectableChannel
- SocketChannel
- ServerSocketChannel
- DatagramChannel
- SelectableChannel
- java.nio.Channels.Channel接口
- 缓冲区(Buffer):负责存储数据
- 选择器(Selector):是SelectableChannel的多路复用器。用于监控SelectableChannel的IO状况。利用 Selector可使一个单独的线程管理多个 Channel。Selector 是非阻塞 IO 的核心。
SelectionKey
当调用 register(Selector sel, int ops) 将通道注册选择器时,选择器对通道的监听事件,需要通过第二个参数 ops 指定。
可以监听的事件类型(用 可使用 SelectionKey 的四个常量 表示):
- 读 : SelectionKey.OP_READ (1)
- 写 : SelectionKey.OP_WRITE (4)
- 连接 : SelectionKey.OP_CONNECT (8)
- 接收 : SelectionKey.OP_ACCEPT (16)
若注册时不止监听一个事件,则可以使用“位或”操作符连接。
DatagramChannel:Java NIO中的DatagramChannel是一个能收发UDP包的通道。
管道 (Pipe)
Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。
样例代码:https://github.com/xulejun/nio-demo