IO模型

Jingxc大约 7 分钟java后端iojava后端

IO模型

很多文章在谈论到BIO、NIO、AIO的时候仅仅是抛出一堆定义,以及一些生动的例子。自己看了以后好像懂了,再仔细一琢磨发现并没有,只是记住了一点定义,对于真正的到底什么是IO,为什么这么定义还是一窍不通,而且也不理解过后就忘,这里自己通俗一点用大白话记录下自己的理解

同步、异步

在java当中,同步异步到底有什么区别呢?

同步指的是程序按照代码的顺序依次执行,直到当前操作完成后再执行下一个操作。而异步则是指程序不必按照代码的顺序依次执行,可以同时执行多个操作,不需要等待当前操作完成。在 Java 中,通常使用回调函数和异步线程来实现异步操作。 例如,在数据读写中,同步读取是指程序会一直阻塞等待数据就绪后才继续往下执行,而异步读取则是在数据准备就绪后再通知程序来处理,程序可以继续执行其他任务而不必等待数据就绪。

是不是还是有点懵,这不就相当于把字面上的意思解释一遍吗?还是不知道是怎么回事...

同步


关键点

在 Java 中,同步 IO 操作是由 Java 虚拟机自己来处理的,而不是交给操作系统处理。

在同步 IO 操作中,Java 应用程序通常使用阻塞式 IO(Blocking IO)来实现(也就是将要介绍的BIO)。阻塞式 IO 通常是指当应用程序发起 IO 操作时,线程会被阻塞,直到操作系统完成了 IO 操作并将结果返回给线程,线程才会继续执行。

Java 应用程序使用的 IO 类库(如 java.ioopen in new window 和 java.nio)实际上是封装了底层的系统调用,将 IO 操作抽象成了 Java 中的对象和方法。当我们调用 IO 方法时,Java 应用程序会调用底层的系统调用来实现 IO 操作

提示

但整个 IO 操作的控制权是在 Java 应用程序中的。

因此,在同步 IO 操作中,Java 应用程序并不需要将 IO 操作交给操作系统处理,而是自己掌控整个 IO 操作的过程。

注意

虽然同步 IO 操作可以实现比较简单,但是当需要处理大量的并发请求时,阻塞式 IO 可能会导致性能瓶颈。因此,Java 中的异步 IO 操作通常更适合处理高并发的场景。

异步


关键点

在 Java 中,异步 IO 操作通常是通过操作系统(OS)来实现的。当我们使用异步 IO 进行文件读写时,Java 实际上是将读写请求发送给操作系统来处理,然后等待操作系统返回结果。

在这个过程中,操作系统实际上是通过底层的系统调用(system call)来完成文件的读写操作。系统调用是操作系统提供的一种机制,用于允许应用程序直接访问操作系统的功能,例如文件读写、进程调度等。

提示

Java 中的异步 IO 操作就是通过操作系统的异步 IO 机制来实现的,可以减少程序的阻塞等待时间,提高程序的性能和并发能力。

在这里的 "OS" 指的是操作系统,例如 Windows、Linux、macOS 等。不同的操作系统实现异步 IO 的方式可能不同,但一般都是通过系统调用实现的。Java 将异步 IO 的处理交给操作系统,是为了充分利用操作系统的异步 IO 功能,提高程序的性能和效率。

相关信息

在 Java 中,异步 IO 操作的实现是通过 NIO(New IO)类库来实现的。Java NIO 提供了一种基于事件驱动的 IO 操作模型,通过注册事件监听器来实现异步 IO 操作。

在进行异步 IO 操作时,Java 应用程序需要将 IO 操作交给操作系统来处理,然后等待操作系统返回结果。为了实现这个过程,Java 应用程序通常需要进行以下步骤:

创建一个 NIO 的 Channel 对象,用于表示一个 IO 通道,例如 FileChannel 或 SocketChannel。

注册一个事件监听器,用于监听 IO 事件,例如读就绪或写就绪事件。Java NIO 提供了一个 Selector 对象,可以用于注册事件监听器,并且可以监听多个 Channel 上的事件。

在事件监听器中处理 IO 事件。当一个 IO 事件发生时,Selector 会通知应用程序,并将该事件封装成一个 SelectionKey 对象。应用程序可以通过 SelectionKey 对象获取到发生事件的 Channel,并进行相应的 IO 操作。

当 IO 操作完成时,通常需要将 IO 结果返回给应用程序。在 Java NIO 中,可以通过 Future 或 CompletionHandler 等方式来处理异步 IO 操作的结果。

需要注意的是,Java NIO 的异步 IO 操作是基于操作系统提供的异步 IO 机制实现的,具体的实现方式可能因操作系统而异。但是,对于 Java 应用程序来说,整个异步 IO 操作的过程都是通过 Java NIO 来实现的。

阻塞、非阻塞

阻塞:进行读写操作时,没有东西可读可写时,程序就进入等待的状态,直到可读或可写为止。(简单的理解就是一根筋,必须要等这件事做完才去做其他的事情,否则一直处于等待的状态。) 非阻塞:进行读写操作时,没有东西可读可写时,Java调用会马上返回 ,程序不会等待。(你先排上号,先去干其他的事情,当叫到你的时候,你再去干这个事情)。

BIO

BIO(Blocking IO):同步并阻塞,服务实现模式为一个连接对应一个线程,即客户端发送一个连接,服务端需要有一个线程来处理。如果连接多了,线程数量不够,就只能等待,即会发生阻塞。

BIO(本人公众号图片)
BIO(本人公众号图片)

提示

BIO:适用于连接数目比较小且固定的架构,对服务器要求比较高,并发局限在应用中

NIO

NIO(Non-blocking IO):同步非阻塞,服务实现模式是一个线程可以处理多个连接,即客户端发送的连接都会注册到多路复用器上,然后进行轮训连接,有I/O请求处理

默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库。

NIO
NIO

提示

NIO:适用于连接数目多且连接比较短的架构,如:聊天服务器,弹幕系统等,编程比较复杂

AIO

AIO(Asynchronous IO):异步非阻塞,引入了异步通道,采用的是Proactor模式,特点是:有效的请求才启动线程,现有操作系统完成在通知服务端。

AIO
AIO

提示

AIO:适用于连接数目多且连接长的架构,如相册服务器

多路io复用

多路复用IO(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型(Redis单线程为什么速度还那么快,就是因为用了多路复用IO和缓存操作的原因)

多路IO复用
多路IO复用
BIONIO
I/O流处理数据I/O块的方式处理数据(buffer)
阻塞的非阻塞的
字节流和字符流操作基于channel通道、buffer缓冲区操作;selector选择器监听
BIO是单向的,要么是输入流要么是输出流NIO是双向的可以往buffer里面读写数据
上次编辑于:
贡献者: jingxc