问答题654/1053阻塞与非阻塞

难度:
2021-11-02 创建

参考答案:

阻塞(Blocking)非阻塞(Non-blocking) 是描述程序在执行输入/输出(I/O)操作时,线程与操作之间的交互方式。它们的区别在于 线程是否会等待 I/O 操作完成,以及 程序是否会继续执行其他任务

1. 阻塞(Blocking)

  • 定义:在阻塞模式下,线程执行某个 I/O 操作时,如果操作无法立即完成(比如没有数据可以读取或无法写入),该线程会被阻塞,直到操作完成,才会继续执行后续代码。也就是说,线程会停下来等待 I/O 操作的结果。

  • 行为

    • 当一个线程执行 I/O 操作时,如果没有立即可用的数据或资源,线程就会被挂起(阻塞),直到数据准备好或 I/O 操作完成。
    • 这会导致程序的执行暂停,不能继续执行其他任务,直到当前 I/O 操作完成。
  • 例子

    • 传统的 InputStream.read()OutputStream.write(),如果没有数据可读取,程序会一直阻塞,直到数据变得可用。
    • 同样,文件读写网络通信 等操作,在阻塞模式下如果等待数据传输或文件操作,会导致线程阻塞。
  • 优缺点

    • 优点
      • 编程模型简单,操作直观。
      • 没有复杂的线程管理和事件处理。
    • 缺点
      • 对于 I/O 密集型应用,线程可能长时间等待,导致 CPU 使用率低,资源浪费。
      • 对并发处理不友好,每个阻塞操作可能会占用一个线程,导致线程池耗尽。

2. 非阻塞(Non-blocking)

  • 定义:在非阻塞模式下,线程执行 I/O 操作时,如果操作无法立即完成(比如没有数据可读取),线程 不会被阻塞,而是立即返回。线程可以继续执行其他任务,直到 I/O 操作完成时,系统通过某种机制(例如回调、事件通知)告知线程操作已完成。

  • 行为

    • 在非阻塞模式下,线程发起 I/O 操作后,如果数据或资源不可用,它会立即返回,并不会等待操作完成。这意味着线程可以继续执行其他任务,而不需要在 I/O 操作上停顿。
    • 线程可以周期性地检查 I/O 操作是否完成,或者通过事件通知等机制来处理完成的 I/O 操作。
  • 例子

    • Java NIO 中的 SocketChannelFileChannel,通过设置为非阻塞模式,执行 read()write() 时,如果数据不可用,方法不会阻塞线程,而是返回一个特殊值(如 -1 或 0)表示当前没有可用数据,线程可以选择继续执行其他任务,或者再次检查数据。
    • Node.js 中,I/O 操作是异步非阻塞的,操作完成时会触发回调函数。
  • 优缺点

    • 优点
      • 适用于高并发环境,能够让线程在等待 I/O 操作时,去执行其他任务,避免了阻塞和资源浪费。
      • 提高了资源的使用效率,避免了线程被无用的 I/O 操作阻塞。
    • 缺点
      • 编程模型相对复杂,需要事件驱动、回调机制或轮询检查来处理 I/O 操作的结果。
      • 需要额外的线程或机制来监控和处理操作结果,增加了编程的复杂性。

3. 阻塞与非阻塞的比较

特性阻塞(Blocking)非阻塞(Non-blocking)
操作行为线程发起 I/O 操作后,会等待直到操作完成。线程发起 I/O 操作后,如果操作无法立即完成,线程立即返回,不会阻塞。
线程状态线程会被挂起,直到 I/O 操作完成。线程不会被挂起,可以继续做其他事情。
适用场景适用于并发性要求不高的场景,或 I/O 操作较少的程序。适用于高并发 I/O 操作的场景,例如高性能服务器、实时应用。
编程复杂度编程较简单,直接处理 I/O 操作结果。编程复杂,需要使用事件驱动或轮询等方式来处理 I/O 操作的结果。
性能影响线程可能会长时间阻塞,导致 CPU 利用率低。更高效的资源使用,避免了 CPU 等待 I/O 操作。

4. 阻塞与非阻塞的典型应用

  • 阻塞模式

    • 文件读取:读取文件时,程序会阻塞直到文件完全读取。
    • 网络请求:传统的 HTTP 客户端请求,发送请求后等待响应。
    • 数据库查询:执行查询时,线程会等待数据库返回查询结果。
  • 非阻塞模式

    • NIO(New I/O):Java NIO 提供了非阻塞 I/O 操作,允许在一个线程中处理多个 I/O 操作,例如 SocketChannelFileChannel
    • 事件驱动编程:如 Node.js,使用异步非阻塞 I/O 模型,能够处理高并发的网络请求,不会阻塞主线程。
    • 多线程或线程池模型:可以通过非阻塞 I/O 配合多个线程或事件循环,来实现高效的并发处理。

5. 阻塞与非阻塞的场景举例

  • 阻塞模式的场景
    • 单线程执行文件读写,等待文件内容被读取完毕。
    • 程序向数据库发送查询请求,等待查询结果返回。
    • 单线程 HTTP 客户端发送请求,等待服务器响应。
  • 非阻塞模式的场景
    • 高并发的 HTTP 服务器(例如,使用 Java NIO 或 Node.js),能同时处理多个请求,而不需要为每个请求等待。
    • 文件服务器在处理多个客户端请求时使用非阻塞模式,避免线程被 I/O 阻塞。
    • 实时游戏或视频流处理,需要避免因 I/O 操作而导致的延迟。

最近更新时间:2024-12-24