Java 中 IO 之 BIO、NIO 和 AIO

简介: IO 是 Input 和 Output 二词的缩写,意为输入和输出,直接来说,实现一般的 I/O 是没有什么难度的,但涉及到多线程时,要解决 I/O 的问题就不是一个简单的事情了,会涉及到同步和异步的问题,阻塞和非阻塞的问题。了解了(非)同步和(非)阻塞之后,我们再来看 I/O,根据是否同步和是否阻塞以及按它们出现的时间顺序,主要划分为 3 种 I/O 技术,分别是 BIO、NIO 和 AIO。当然,并不是只有这几种,还有其他的 I/O 类型。

一、IO

IO 是 Input 和 Output 二词的缩写,意为输入和输出,直接来说,实现一般的 I/O 是没有什么难度的,但涉及到多线程时,要解决 I/O 的问题就不是一个简单的事情了,会涉及到同步和异步的问题,阻塞和非阻塞的问题。

1.1 同步和异步

同步可以借用多线程来方便理解,多条线程,从字面意思上来看,当他们在同一直线上时,就是同步,反之则是异步。那什么是在同一直线上呢?简单说就是,它们都在处理同时事件,比如同时运行某个函数,调用或修改某个变量。

从这里我们不难看出,同步有时是会产生一些问题的,比如同时修改某个变量。从现实角度来看,这是不可能修改成功的,毕竟是完完全全同时嘛。但是,我们知道计算机的每个 CPU 执行多线程实际并非真的同时干两个事情,它只是将时间分片了,一会儿做这个线程的事情,一会做另外一个线程的事情,由于 CPU 切换任务和执行任务的速度非常非常快,因此从宏观时间尺度上来看,就好像多个线程在同时运行,但实际在微观时间尺度上,它们仍然是单线程的。

多线程

接上面的说,那么计算机的两个线程同时修改某个变量后,必然有一个线程先对这个变量进行修改,另外一个线程再对这个线程进行修改,由于分片数量和执行速度不能保证完完全全相同,所以我们无法预测到底是哪个线程先对这个变量进行的修改,那么这就会产生一系列无法预知的问题。为此,异步操作诞生了!

从程序优化的角度上看,异步操作优于同步操作,但相应地,实现难度会大一些。

1.2 阻塞和非阻塞

最典型的阻塞就是终端等待用户输入,Java 里面使用 Scanner 类时,在不做多线程等处理时,要一直等到用户在终端输入字符后,Scanner 类后面的代码才能运行。而非阻塞呢,在界面编程里面体现的非常明显,窗口的显示实际可以看作是一个大循环,它在每一次循环中都在刷新着窗口,但我们在窗口中的操作并运行一些计算的时候呢,界面也一直都在,它并不会因为我们操作了什么而产生了阻塞,导致窗口没有变化(不刷新)了。

从阻塞和非阻塞的含义上来看,大部分时间我们都希望程序是非阻塞的,因为阻塞的情况下,阻塞处后面的程序无法运行,这就浪费计算机的性能了,等阻塞完之后再执行后面的程序,会产生时间上的消耗,使用户产生延迟感,这是不好的,为了解决这个问题,非阻塞操作产生了!

从程序优化的角度上看,非阻塞操作优于阻塞操作,但相应地,非阻塞的实现难度大一些。

了解了(非)同步和(非)阻塞之后,我们再来看 I/O,根据是否同步和是否阻塞以及按它们出现的时间顺序,主要划分为 3 种 I/O 技术,分别是 BIO、NIO 和 AIO。当然,并不是只有这几种,还有其他的 I/O 类型。

二、BIO

BIO 是 Blocking I/O 的缩写,意为同步阻塞式 I/O,Blocking 是阻塞的意思。

BIO 是最基本的 I/O 处理模式。在这种模式下,当一个 I/O 操作正在进行时,会阻塞其他所有操作,直到这个 I/O 操作完成。这种模式的优点是编程模型简单,适合请求不高并发、任务简单的场景。但是,对于高并发的场景,BIO 可能会导致大量的线程阻塞,消耗大量的系统资源,性能较低。

三、NIO

NIO 是 Non-blocking I/O 的缩写,代表同步非阻塞式 I/O,Non-blocking 是非阻塞意思。

NIO 是对 BIO 的一种改进。在这种模式下,当一个 I/O 操作正在进行时,不会阻塞其他操作。NIO 通过使用 Buffer(缓冲区)和 Channel(通道)进行数据的传输,以及使用 Selector(选择器)进行多路复用,可以同时处理多个客户端的连接和请求。这种模式的优点是可以处理高并发的场景,但是编程模型相对复杂。

下面是 NIO 的主要组件:

Channel(通道):Channel 是一个可以进行 I/O 操作的连接点。所有的数据都必须通过 Channel 读取或者写入。Channel 的主要实现包括 FileChannel(用于文件 I/O)、DatagramChannel(用于 UDP I/O)和 SocketChannel(用于 TCP I/O)。

Buffer(缓冲区):Buffer 是一个容器,用于在 Channel 和程序之间传输数据。当我们从 Channel 读取数据时,数据会被读入 Buffer;当我们向 Channel 写入数据时,数据会从 Buffer 写入。

Selector(选择器):Selector 是一个可以监控多个 Channel 的 I/O 状态(如:连接、读取、写入)的组件。通过 Selector,我们可以使用一个线程来处理多个 Channel 的 I/O 操作。

虽然 NIO 可以处理高并发场景,但当并发数量过大时,由于 NIO 的原理,它仍然会出现类似 BIO 阻塞的情况。

四、AIO

AIO 是 Asynchronous I/O 的缩写,意为异步非阻塞式 I/O,Asynchronous 是异步的意思。按照我们之前说的,这已经属于是效果最好,实现最难的 I/O 了。

AIO 是一种更高级的 I/O 处理模式。在这种模式下,一个 I/O 操作可以在后台异步地进行,当操作完成时,会通知相应的线程进行处理。这种模式的优点是可以处理高并发的场景,并且编程模型相对简单。但是,由于 AIO 是在操作系统级别进行异步操作,所以对操作系统的要求较高。

五、总结

按照时间出现的顺序,分别是 BIO、NIO 和 AIO,按照技术实现难度,分别是 BIO、NIO 和 AIO。总结为下表:

I/O BIO(同步阻塞式) NIO(同步非阻塞式) AIO(异步非阻塞式)
是否同步
是否非阻塞
出现时间 最早 中等 最迟
实现难度 简单 中等 困难
实现效果 中等
代码维护难度 中等

这三者的应用场景如下:

  • BIO 适用于单线程或少量并发的场景,每个 I/O 操作都会阻塞当前线程;
  • NIO 适用于需要处理大量并发连接的场景,一个线程可以同时处理多个 I/O 操作;
  • AIO 适用于需要处理大量并发操作且不希望线程阻塞的场景,通过回调函数处理 I/O 操作的完成;

有人就要问了,怎么没有 异步阻塞式 I/O 呢?这是个好问题。

异步阻塞式 I/O 也不是没有,只不过它的叫法与其他的不太一样,它叫做 I/O 多路复用(I/O Multiplexing)。这里不详细展开讲述了,后面会单独出一片文章进行讲解。

目录
相关文章
|
11天前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
1月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
67 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
1月前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
28 2
|
2月前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
1月前
|
Java 数据处理 开发者
揭秘Java IO流:字节流与字符流的神秘面纱!
揭秘Java IO流:字节流与字符流的神秘面纱!
35 1
|
1月前
|
自然语言处理 Java 数据处理
Java IO流全解析:字节流和字符流的区别与联系!
Java IO流全解析:字节流和字符流的区别与联系!
74 1
|
28天前
|
Java
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
43 0
|
1月前
|
存储 Java 程序员
【Java】文件IO
【Java】文件IO
35 0
|
Java
Java NIO系列教程三
​ 今天主要给大家介绍的是Buffer的基本使用这个也是NIO里面最总要的概率之一,里面的操作也是有一些复杂的同时也是需要大家必须要重点掌握的知识点,同时也介绍了一下Selector的用法下一篇文章我们将为大家介绍Pipe管道以及FileLock文件锁这也是NIO里面最后的一分部内容了。
99 0
|
安全 Java API
Java NIO系列教程四【完】-管道-文件锁-异步写入
​ 到此位置NIO的所有的内容都结束了,对于NIO来说主要是各种概念需要大家去理解然后有很多的用法和api也需要大家去熟悉所以想把NIO学懂学好其实并不容易一定要多写案例去测试巩固,也预祝大家能把NIO的知识看懂理顺!!!
99 0