同步、异步和阻塞、非阻塞

  • 同步、异步是消息通知机制
  • 阻塞、非阻塞是等待通知时的状态

Java 3 种 IO 方式

Java IO 的方式通常分为阻塞的 BIO(Blocking IO)、同步非阻塞的 NIO(New IO) 和异步非阻塞的 AIO(Asynchronous IO)。

JDK1.4 之前只支持 BIO,JDK1.4 以后开始支持 NIO,JDK1.7 开始支持 AIO。

1. BIO

BIO 是同步阻塞的。服务器的模式为一个连接一个线程

客户端有连接请求时,就需要启动一个线程进行处理。如果这个连接不做任何事情,就会造成不必要的开销,可以通过线程池机制改善。

2. NIO

NIO 是同步非阻塞的。服务器模式为一个请求一个线程

NIO 最重要的地方是当一个连接建立后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程即可,当这个线程中的多路复用器进行轮询时,发现连接上有请求的话,才开启一个线程进行处理。

3. AIO

AIO 是异步阻塞的。服务器模式为一个有效请求一个线程

客户端的 IO 请求都是由操作系统完成,再通知服务器去启动线程进行处理。真正的 IO 读写已经由内核完成了。

BIO 和 NIO 的区别

  • 是否阻塞
    BIO 是阻塞的,NIO 是非阻塞的。
    BIO 中一个线程调用 read() / write() 时,该线程被阻塞;
    NIO 中一个线程从 Channel 中读取数据到 Buffer 中,可以继续做别的操作,当数据读取到 Buffer 中后,线程再继续处理数据;一个线程请求写入数据到某个 Channel,但不需要等待完全写入,该线程可进行别的操作。
  • 缓冲区(Buffer)
    BIO 是面向流的,NIO 是面向缓冲区。
    发送给一个通道的所有数据都必须首先放到缓冲区中,同样地,从通道中读取的任何数据都要先读到缓冲区中。也就是说,不会直接对通道进行读写数据,而是要先经过缓冲区
  • 通道(Channel)
    NIO 通过 Chammel 进行读写。
    通道和流的不同之处在于:流只能在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类),而通道是双向的,可以用于读、写或者同事用于读写。
    通道只能和缓冲区交互,因为有缓冲区,通道可以异步读写。
  • 选择器(Selector)
    NIO 中一个线程使用一个选择器 Selector,通过轮询的方式去监听多个 Channel 上的事件。从而让一个线程就可以处理多个事件。
    使用 Selector 的好处:使用更少的线程就可以来处理通道了,相比使用多个线程,减少了线程上下文切换带来的开销

应用场景

  • BIO 适用于连接数目少且固定的架构。这种方式对服务器要求比较高,并发局限于应用中,程序直观简单,容易理解。
  • NIO 适用于连接数目多且连接比较短的架构。这种方式并发局限于应用中,但编程较复杂。
  • AIO 适用于连接数目多且连接比较长的架构。这种方式充分调用服务器的并发操作,但是编程复杂。