阻塞与非阻塞、同步与异步总结

1. 阻塞(Blocking)

  • 线程发起 IO 或等待某个资源时 无法继续执行任务,被操作系统挂起
  • 线程状态通常是 WAITING / TIMED_WAITING / BLOCKED,不会占用 CPU 时间片。
  • 等待条件满足后(如有数据到达或收到信号),线程被唤醒才能继续执行。
  • 线程池里,这个线程仍然 占用一个线程槽,只是没有在跑代码。

举例

  • 调用 InputStream.read() 等待网络数据 → 阻塞
  • 调用 Future.get() 等待结果 → 阻塞

阻塞的缺点

  1. 资源浪费:线程被阻塞时无法执行其他任务,但持续占用线程资源。
  2. 可伸缩性差:每个连接关联一个线程,连接数增加线程数增加。
  3. 上下文切换开销大:频繁线程切换降低系统性能。
  4. 处理复杂度高:需要额外线程管理和同步机制。

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:线程完全不阻塞,通过回调处理 → 异步非阻塞
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐