NIO
三大组件
- channel:通道
- BIO中的stream是单向的,例如FleInputStream对象只能进行读取数据的操作
- NIO中的通道(channel)是双向的,可以进行读写操作
- 常用的channel:
- FileChannel:用于文件数据的读写
- DatagramChannel:UDP的数据读写
- ServerSocketChannel:TCP的数据读写
- SocketChannel:TCP的数据读写
- buffer:缓冲区(内存),实际上是一个容器,一个特殊的数组缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况
- Buffer是一个顶级父类,是一个抽象类,子类有:
- ByteBuffer:存储字节数据到缓冲区
- ShortBuffer:存储字符串数据到缓冲区
- CharBuffer:存储字符数据到缓冲区
- IntBuffer:存储整数数据到缓冲区
- LongBuffer:存储长整型数据到缓冲区
- DoubleBuffer:存储小数到缓冲区
- FloatBuffer:存储小数到缓冲区
- Buffer是一个顶级父类,是一个抽象类,子类有:
- selector:选择器,能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取事件然后针对事件进行相应的处理。这样就可以用一个单线程去管理多个通道,也就是管理多个连接。这样使得只有在连接真正有读写事件发生时,才会调用函数来进行读写,就大大的减少了系统的开销,并且不必为每个连接都创建一个线程,不用去维护多个线程,并且避免的多线程之间上下文切换导致的开销
ByteBuffer
- buffer的正确使用姿势:
- 向 buffer 写入数据,例如调用 channel.read(buffer)
- 调用 flip() 切换至读模式
- 从 buffer 读取数据,例如调用 buffer.get()
- 调用 clear() 或 compact() 切换至写模式
- 重复 1~4 步骤
- ByteBuffer 结构
- capacity:容量
- position:位置
- limit:写入限制
- ByteBuffer 常用方法
- 分配空间
- ByteBuffer.allocate(16)
- ByteBuffer.allocateDirect(16)
- 分配空间
- 写入数据
- 调用 channel 的 read 方法
- 调用 buffer 自己的 put 方法
- 读取数据
- 调用 channel 的 write 方法
- 调用 buffer 的 get 方法
注意:get 方法会让 position 读指针向后走,如果想重复读取数据
- 可以调用 rewind 方法将 position 重新置为0
- mark:做一个标记,记录 position 位置;reset :是将position 重置到 mark 的位置
- 或者调用 get(int i) 方法获取索引 i 的内容,它不会移动指针
- Scattering Reads:分散读取
- Gathering Writes:集中写入
文件编程
- FileChannel:只能工作在阻塞模式下
- 获取
- 通过 FileInputStream 获取的 channel 只能读
- 通过 RandomAccessFile 是否能读写根据构造 RabdomAccessFile 时的读写模式决定
- 通过 FileOutputStream 获取的 channel 只能写
- 读取:会从 channel 读取数据填充ByteBuffer ,返回值表示读到了多少字节,-1表示到达了文件的末尾
- 写入
- 关闭:channel 必须关闭
- 获取
- 两个 Channel 传输数据:transferTo()
网络编程
- 非阻塞和阻塞
- 多路复用(selector)
- select何时不阻塞
- 事件发生时
- 客户端发起连接请求,会触发accept事件
- 客户端发送数据过来,客户端正常、异常关闭时,都会触发read事件,另外如果发送的数据大于buffer 缓冲区,会触发多次读取事件
- channel 可写,会触发 write 事件
- 在linux 下nio bug发生时
- 调用 selector.wakeup()
- selector 所在线程 interrupt
- 调用 selector.close()
- 事件发生时
- select何时不阻塞
- IO 模型
- 阻塞 IO
- 非阻塞 IO
- 多路复用
- 信号驱动
- 异步 IO
NIO vs BIO
- stream vs channel
- stream 不会自动缓数据,channel 会利用系统提供的发送缓冲区、接收缓冲区(更为底层)
- stream 仅支持阻塞API,channel 同时支持阻塞、非阻塞API,网络channel 可配合selector 实现多路复用
- 二者均为双全工,即读写可同时进行
- IO 模型:同步阻塞、同步非阻塞、同步多路复用、异步非阻塞
- 同步:线程自己去获取结果(一个线程)
- 异步:线程自己不去获取结果,而是由其他线程送结果(至少两个线程)