IO阻塞和异步(NIO,BIO,AIO)
可伸缩性差:阻塞模式下,每个连接通常都会关联一个线程,当连接数增加时,线程数也会相应增加,这样会占用大量的系统资源,导致系统的可伸缩性较差。资源浪费:在阻塞模式下,当一个线程被阻塞时,它无法执行其他任务,但却会持续占用系统的线程资源。上下文切换开销大:在阻塞模式下,由于线程被阻塞时需要切换到其他线程执行,频繁的线程切换会导致较大的上下文切换开销,降低系统的性能。处理复杂度高:在阻塞模式下,需要额外
·
阻塞与非阻塞、同步与异步总结
1. 阻塞(Blocking)
- 线程发起 IO 或等待某个资源时 无法继续执行任务,被操作系统挂起。
- 线程状态通常是
WAITING/TIMED_WAITING/BLOCKED,不会占用 CPU 时间片。 - 等待条件满足后(如有数据到达或收到信号),线程被唤醒才能继续执行。
- 线程池里,这个线程仍然 占用一个线程槽,只是没有在跑代码。
举例
- 调用
InputStream.read()等待网络数据 → 阻塞 - 调用
Future.get()等待结果 → 阻塞
阻塞的缺点
- 资源浪费:线程被阻塞时无法执行其他任务,但持续占用线程资源。
- 可伸缩性差:每个连接关联一个线程,连接数增加线程数增加。
- 上下文切换开销大:频繁线程切换降低系统性能。
- 处理复杂度高:需要额外线程管理和同步机制。
2. 非阻塞(Non-blocking)
- 线程发起操作后 立即返回,继续执行自己的任务。
- IO 结果通过 事件或回调 处理。
- 线程池线程可以 复用或去处理其他任务。
特性对比
| 特性 | 阻塞 | 非阻塞 |
|---|---|---|
| 线程状态 | WAITING/阻塞 | RUNNABLE(继续执行) |
| CPU 占用 | 0(挂起) | 可占用或去做其他任务 |
| 线程池占用 | 占用线程槽 | 可以释放线程,复用 |
| 等待方式 | 等待事件/信号 | 不等,靠回调或轮询处理结果 |
一句话总结
- 阻塞 = 线程挂起等待资源/信号
- 非阻塞 = 线程发起操作后立即返回,IO 结果通过事件或回调处理
3. 异步(Asynchronous)
- 异步关注谁等待任务完成:调用者发起任务后 不必等待结果,可以先去做其他事情。
- 异步任务内部可以是 阻塞 IO 也可以是 非阻塞 IO → 性能差异很大。
阻塞 vs 异步的关系
| 异步/同步 | 阻塞 | 非阻塞 | 说明 |
|---|---|---|---|
| 同步阻塞 | ✅ | ❌ | 最常见:传统 Socket、RestTemplate,线程等待结果返回 |
| 同步非阻塞 | ❌ | ✅ | NIO 轮询,线程自己检查是否有结果完成 |
| 异步阻塞 | ✅ | ❌ | 提交任务后由系统异步执行,但执行线程可能做阻塞 IO |
| 异步非阻塞 | ❌ | ✅ | 高性能 IO,如 Netty、OkHttp enqueue、WebFlux,线程发出请求后立即返回,IO 完成通过回调通知 |
4. Java IO 模型
| IO 类型 | 阻塞/非阻塞 | 同步/异步 | 线程占用 | 说明 |
|---|---|---|---|---|
| BIO | 阻塞 | 同步 | 阻塞线程池线程 | 简单易用,低并发适用 |
| NIO | 非阻塞 | 同步 | 轮询检查,不占用线程池线程 | 高并发,线程少,多路复用 |
| AIO | 非阻塞 | 异步 | 线程完全释放,通过回调处理 | 高并发、大量连接,线程资源利用率高 |
总结
- BIO:简单易用,但线程占用高 → 阻塞线程池线程
- NIO:线程不被 IO 阻塞,但要轮询 → 非阻塞同步
- AIO:线程完全不阻塞,通过回调处理 → 异步非阻塞
更多推荐

所有评论(0)