空空叶博客 学习与开发博客

java nio研究

2018-03-12
kongkongye
       

包括BIO(阻塞式),NIO(非阻塞式),AIO(异步)相关的介绍与比较.

todo: 实现代码demo,加深理解

相关概念

  • 阻塞/非阻塞IO: 数据没有就绪时等待/直接返回
  • 同步/异步IO: 关键在于数据拷贝阶段是由用户线程还是内核完成(因此异步IO必须有操作系统的底层支持)

IO可以分为两个阶段: 等待就绪操作. 可以看出来,阻塞/非阻塞反映在第一阶段,同步/异步则反映在第二阶段.

NIO/AIO中相关概念

  • Buffer(缓冲区): 包含一些要写入或读出的数据,在nio/aio里,所有数据都是用缓冲区处理的.
  • Channel(通道): 类似于stream(流),但通道是双向的,可以同时读写(另外底层操作系统的通道一般都是全双工的,因此channel比stream更适合进行描述)
  • Selector(多路复用器): 可以在Selector上注册Channel,在NIO中Selector会不断轮询获取就绪的Channel(其上有读或写事件)(并可以通过SelectionKey可以获取就绪的channel集合进行后续操作)
  • event dispatcher(事件分发器): 将事件源分发给处理者(回调函数)

四种IO模式介绍

BIO(Blocking IO)

传统的BIO即阻塞式IO编程模型,这种方式通常在接受一个新连接后,就开一个新线程去同步阻塞式地处理请求, 从代码角度看就是socket.accept(), socket.read(),socket.write()这几个方法都是同步阻塞的. 这种方式的缺点很明显:

  1. 连接增多时,会创建大量线程,每个线程都会占用不小的内存资源
  2. 线程上下文切换的代价是昂贵的,大量线程会导致大量的切换,但因为大量线程处于阻塞状态(切进来没做任意事又切出去),因此会存在大量无意义的切换.造成cpu负载很高,但工作效率很低.

伪异步IO

即使用线程池,将新建线程改为提交到线程池里,实现N连接:M线程(N可以远大于M).

但这种方式底层还是使用的同步阻塞IO,当连接超过线程池上限时,其它连接只能等待.

当数据量大,网络慢时,一个连接仍然会长时间占用线程.

NIO(Non-Blocking IO)

java新的NIO模型即非阻塞式IO编程模型,里面使用了事件模型.

event dispatcher(事件分发器)的模式为: Reactor(反应器),此模式基于同步IO, 就是在读写就绪了后,分发器会通知回调处理者,再由处理者自行去读写(这个读写是同步阻塞的)

NIO2/AIO(Async IO)

java的nio2.0引用了新的AIO概念,即异步IO.

event dispatcher(事件分发器)的模式为: Proactor,此模式基于异步IO, 就是在读写就绪了后,分发器会给系统底层发送读写请求,并且在读写完成之后, 再通知回调处理者(这才是系统级别的,真正的异步)

四种IO模式比较

IO模式 BIO 伪异步IO NIO AIO
连接数:IO线程 1:1 N:M(N>=M) N:1 N:0
IO阻塞类型 阻塞 阻塞 非阻塞 非阻塞
IO同步类型 同步 同步 同步(多路复用) 异步
API使用难度 简单 简单 复杂 一般
调试难度 简单 简单 复杂 复杂
可靠性 非常差
吞吐量

其中NIO与AIO主要差别就在于AIO会在读写完成后再通知处理者,而NIO会在读写就绪时通知处理者去读取 (虽然这个读取是同步阻塞的,但通常非常快,属于memory copy,基本上不耗时,因此效率上NIO与AIO差别可能不会很大)


相似文章

上一篇 链路层研究

下一篇 思维导图

目录