I/O 模型简单理解为:就是使用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能。
Java 支持 3 种网络编程模型:BIO、NIO、AIO。
BIO(Blocking I/O)
- 阻塞模式:在BIO模式下,每个I/O操作都会阻塞当前线程,直到读取或写入完成。也就是说,在一个线程执行I/O操作时,其它线程(或操作)需等待。
- 线程开销:通常每个客户端请求都对应一个线程,这意味着大量的线程可能导致资源消耗高,特别是线程上下文切换的开销。
- 适用场景:适用于连接数较少且固定的场合,比如数据库连接池或者文件I/O。
Java NIO(Non-blocking I/O)
- 非阻塞模式:NIO引入了Channels和Buffers以及选择器(Selectors),可以在不阻塞线程情况下进行I/O操作。
- 单线程管理多连接:利用选择器,一个线程可以管理多个通道(即连接),大大减少了线程数量,提高资源利用率。
- 适用场景:适用于较多连接,且对实时性要求不高的场合,通常用于高并发场景下的服务器端编程。
Selector
Selector多路复用器算是对linux下的select/poll/epoll进行封装,selector可以有多种实现,linux系统下默认使用epoll的实现方式。
Java 的 NIO 使用了非阻塞的 I/O 方式。可以用一个线程处理若干个客户端连接,就会使用到 Selector(选择器)。
Selector 能够检测到多个注册通道上是否有事件发生(多个 Channel 以事件的形式注册到同一个 selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。
只有在连接真正有读写事件发生时,才会进行读写,减少了系统开销,并且不必为每个连接都创建一个线程,不用维护多个线程。
避免了多线程之间上下文切换导致的开销。
Java AIO(Asynchronous I/O)
- 异步非阻塞模式:AIO进一步引入了异步通道,从底层支持异步读写操作,包括连接、读写的完成都会通知应用。
- 回调机制:完成操作后,通过回调函数来处理结果。
- 适用场景:复杂的高并发应用,支持异步调用,适合于对延迟敏感的场景。