BIO、NIO、AIO详解

一、基础概念: 阻塞/非阻塞、同步/异步

1.1 阻塞/非阻塞和同步/异步这两个概念的区别

1.1.1 他们不是一回事,是两个不同维度

概念 讨论的层面 问题核心
阻塞/非阻塞 线程等待状态 当线程发起I/O操作时,是"停下来等结果",还是"立刻返回自己干别的"
同步/异步 结果通知方式 谁负责通知I/O操作完成?是自己主动去取,还是系统回调告诉你

可以这么理解:

  • "阻塞/非阻塞"->线程等不等
  • "同步/异步"->结果谁来告诉你

两者的本质区别总结一句话: "阻塞/非阻塞"关注的是线程是否空等,"同步/异步"关注的是I/O完成后通知的方式。

1.1.2 一个生活例子: 点外卖 🍔

我们用"点外卖"的例子讲这四种组合:
①同步阻塞(最传统的方式)

你打电话点外卖 → 然后就在家门口等着,直到外卖送到,什么都不干。

  • 线程: 等待中(被阻塞)
  • 结果通知: 靠你自己等
  • 举例: Java的BIO模型
java 复制代码
# 类比
read() // 没数据?我就一直等...

②同步非阻塞

你打电话点外卖 → 然后每隔一会儿跑去门口看看外卖到了没。

  • 线程: 没有被阻塞(可以做别的事)
  • 结果通知: 仍然是你自己反复检查
  • 举例: Java 的 NIO(Selector 轮询)
java 复制代码
# 类比
while(true){
    if(channel.read(buffer) > 0){ 
        // 终于有数据了!
    } else {
        // 没有数据,继续干别的
    }
}

③异步阻塞(理论上存在但不常用)

你打电话点外卖 → 外卖系统说"到了我会打你电话",但你却一直拿着手机等电话(别的事也不做)。

  • 线程: 阻塞(在等通知)
  • 结果通知: 系统(外卖)回调告诉你
    实际系统中不常用

④异步非阻塞(最现代、最高效)

你打电话点外卖 → 系统登记好 → 你继续干别的,外卖送到后系统自动发短信通知你"到了"。

  • 线程: 不阻塞
  • 结果通知: 系统主动回调
  • 举例: Java AIO(异步通道回调 CompletionHandler)
java 复制代码
# 类比
channel.read(buffer, attachment, new CompletionHandler<Integer, Object>() {
    @Override
    public void completed(Integer result, Object attachment) {
        // 有数据可读了!系统通知我来处理
    }
});

二、三种I/O模型概述

2.1 BIO(同步阻塞IO)

BIO(Blocking I/O):指的是当线程执行 I/O 操作时,如果数据没准备好,就会一直等待,直到数据可用或发生异常才返回。

在 Java 网络编程中,BIO 典型表现就是:

一个连接对应一个线程,读写操作会阻塞线程。

2.2 NIO(同步非阻塞IO/多路复用IO)

目的是:让一个线程能同时管理多个连接,实现高并发的网络通信。

与BIO的明显区别是,发起第一次请求后,线程并没有被阻塞,它反复检查数据是否准备好,把原来大块不能用的阻塞时间分成了许多"小阻塞"(检查),所以进程不断有机会被执行。这个检查有没有准备好数据的过程有点类似于"轮询"。
核心组件:

  • Channel:类似传统 I/O 的流,但支持非阻塞操作
  • Buffer:用于数据的读写中转
  • Selector(选择器):核心机制,将多个 Channel 注册到一个 Selector 上,由它监控这些通道的 I/O 事件



IO多路复用

NIO 是上层 API 框架,是 Java 对这种能力的封装;NIO 的 Selector 就是"多路复用器",本质上就是在调用 select / epoll。

  • select: 注册事件由数组管理, 数组是有长度的, 32位机上限1024, 64位机上限2048。轮询查找时需要遍历数组。
  • poll:把select的数组采用链表实现,因此没了最大数量的限制
  • epoll方式:基于事件回调机制,回调时直接通知进程,无须使用某种方式来查看状态。

2.3 AIO(异步非阻塞IO)

核心思想: 应用线程发起 I/O 操作后立即返回,由操作系统在操作完成时自动通知应用(回调)。

也就是说:

线程发起 I/O 请求后不用自己轮询、也不会阻塞,当数据准备好(或者写完)时,系统会调用回调函数 CompletionHandler 来处理结果。

相关推荐
青鱼入云2 分钟前
redisson介绍
redis·1024程序员节
默 语3 小时前
MySQL中的数据去重,该用DISTINCT还是GROUP BY?
java·数据库·mysql·distinct·group by·1024程序员节·数据去重
哲Zheᗜe༘4 小时前
了解学习Redis主从复制
数据库·redis·学习
oDeviloo4 小时前
新版IntelliJ IDEA个性化设置兼容老版习惯
java·ide·intellij-idea
一只小透明啊啊啊啊5 小时前
Java Web 开发的核心组件:Servlet, JSP,Filter,Listener
java·前端·servlet
一条懒鱼6665 小时前
Redis Sentinel哨兵集群
数据库·redis·sentinel
spencer_tseng6 小时前
Eclipse Uninstall Software
java·ide·eclipse
嗯、.6 小时前
使用 iText 9 为 PDF 添加文字水印的完整实战
java·pdf·itext
怪兽20146 小时前
缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题
java·缓存·面试
皮皮林5516 小时前
Java 25 正式发布:更简洁、更高效、更现代!
java