12 BIO,NIO,AIO的区别

vvEcho 2024-01-24 10:33:23
Categories: Tags:

BIO、NIO、AIO 是Java中处理I/O操作的不同方式,它们的区别如下:

  1. BIO(Blocking I/O):阻塞式I/O,即在执行I/O操作时,当前线程会被阻塞,直到I/O操作完成。这种方式适用于简单的I/O操作,但当有大量的并发请求时,性能较差。

核心机制:

每个连接对应一个独立线程,线程在I/O操作期间被完全阻塞,直到数据就绪或操作完成 1 3。
典型实现如ServerSocket和Socket,通过accept()和read()方法阻塞等待客户端请求

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.*;

public class BioExample {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("input.txt");
int data = fis.read();
while (data != -1) {
System.out.print((char) data);
data = fis.read();
}
fis.close();
}
}

在这个例子中,我们使用FileInputStream进行文件读取,由于使用了阻塞式I/O,所以在读取文件时,当前线程会被阻塞,直到文件读取完成。

  1. NIO(Non-blocking I/O):非阻塞式I/O,即在执行I/O操作时,不会阻塞当前线程,而是通过回调函数或轮询的方式检查I/O操作是否完成。这种方式适用于高并发的场景,性能较好。

核心机制:

基于多路复用器(Selector),单个线程可监听多个通道(Channel)的就绪事件(如读/写),通过轮询实现非阻塞 2 4。
使用Buffer和Channel替代传统流式I/O,支持零拷贝技术提升性能

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.nio.*;
import java.nio.channels.*;

public class NioExample {
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable()) {
// 处理接受连接的逻辑
} else if (key.isReadable()) {
// 处理读取数据的逻辑
}
iterator.remove();
}
}
}
}

在这个例子中,我们使用SelectorServerSocketChannel进行非阻塞式文件读取,通过轮询的方式检查文件读取是否完成。

  1. AIO(Asynchronous I/O):异步I/O,由操作系统内核来完成I/O操作,减少线程切换开销,提高性能;线程完全非阻塞,线程资源利用率极高,适合海量并发。

核心机制:

基于异步回调或事件驱动,由操作系统内核完成I/O操作后通知应用程序,无需线程主动等待
如AsynchronousSocketChannel和CompletionHandler,操作发起后立即返回,内核完成读写后通过回调通知结果

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.nio.*;
import java.nio.channels.*;
import java.util.concurrent.*;

public class AioExample {
public static void main(String[] args) throws IOException, InterruptedException {
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(Paths.get("input.txt"), StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;
long count = fileChannel.size();

Future<Integer> operation = fileChannel.read(buffer, position);
while (!operation.isDone()) {
// 可以执行其他任务,不会被阻塞
}

int bytesRead = operation.get(); // 获取实际读取的字节数
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
fileChannel.close();
}
}

在这个例子中,我们使用AsynchronousFileChannel进行异步文件读取,通过回调函数通知文件读取完成。

总结:BIO-阻塞式io,通俗理解去银行取钱,银行只开了一个窗口得一个一个来取【线程阻塞,资源消耗大】
NIO-非阻塞式io,通俗理解去银行取钱,取完号后可以自由活动,但是得定期看看电子大屏看是否轮到自己,当窗口准备好时,用户需自行前往办理(数据拷贝仍需阻塞等待)【多路复用,主动轮询就绪事件】
AIO-异步非阻塞io,通俗理解你要取钱,但是你没有时间自己去取,你向银行提交申请后,银行派人把钱给你送来【内核完成所有操作并主动回调,用户全程无感】