- BIO(Blocking I/O,阻塞式I/O)
- 概念与原理:
- BIO是一种最基本的I/O模型。当一个线程发起一个I/O操作(如读取文件或网络通信)时,该线程会被阻塞,直到这个I/O操作完成。例如,在进行网络通信时,服务器端使用
ServerSocket
来监听端口,当有客户端连接请求时,accept
方法会阻塞,直到有新的连接建立。之后,在读取或写入数据时,read
和write
方法也会阻塞线程,直到数据读取或写入完成。
- BIO是一种最基本的I/O模型。当一个线程发起一个I/O操作(如读取文件或网络通信)时,该线程会被阻塞,直到这个I/O操作完成。例如,在进行网络通信时,服务器端使用
- 代码示例(以Java网络编程为例):
```java
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
- 概念与原理:
public class BIOServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器已启动,等待客户端连接...");
// 阻塞,等待客户端连接
Socket socket = serverSocket.accept();
System.out.println("客户端已连接");
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
// 阻塞,等待读取数据
int length = inputStream.read(buffer);
System.out.println("收到客户端消息:" + new String(buffer, 0, length));
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- **应用场景与优缺点**:
- **应用场景**:适用于连接数比较少且连接比较稳定的场景,如简单的文件传输服务、数据库连接等。因为它的编程模型简单直接,容易理解和实现。
- **优点**:编程模型简单,对于初学者来说容易上手;在处理少量连接时,性能可以满足需求。
- **缺点**:一个线程只能处理一个连接,当连接数增多时,需要创建大量的线程来处理,会导致系统资源的浪费(线程上下文切换开销等);线程阻塞会导致效率低下,特别是在等待I/O操作完成的过程中,线程无法执行其他任务。
2. **NIO(Non - Blocking I/O,非阻塞式I/O)**
- **概念与原理**:
- NIO是一种基于通道(Channel)和缓冲区(Buffer)的I/O模型。与BIO不同,在NIO中,线程发起I/O操作后不会被阻塞。例如,通道在进行数据读取或写入操作时,如果没有数据可读或可写,不会像BIO那样阻塞线程,而是会返回一个特殊的值(如`-1`表示没有数据可读),这样线程就可以去做其他事情。NIO还引入了选择器(Selector),它可以同时监听多个通道的事件(如可读、可写、连接等事件),从而实现一个线程管理多个I/O通道。
- **代码示例(以Java NIO网络编程为例)**:
```java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NIOServer {
public static void main(String[] args) {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器已启动,等待客户端连接...");
while (true) {
// 阻塞,等待事件发生
int readyChannels = selector.select();
if (readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = server.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int length = socketChannel.read(buffer);
if (length > 0) {
buffer.flip();
System.out.println("收到客户端消息:" + new String(buffer.array(), 0, length));
}
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 应用场景与优缺点:
- 应用场景:适用于高并发的网络应用,如高性能的网络服务器、大规模的文件读写等场景。因为它可以用较少的线程来处理多个连接,提高了资源利用率和系统的吞吐量。
- 优点:一个线程可以管理多个连接,减少了线程上下文切换的开销,提高了系统资源的利用率;非阻塞的I/O操作可以让线程在等待I/O操作时去处理其他任务,提高了系统的并发性能。
- 缺点:编程模型相对复杂,需要理解通道、缓冲区和选择器等概念;在处理复杂的业务逻辑时,可能需要更多的代码来处理各种I/O事件和状态。
- AIO(Asynchronous I/O,异步I/O)
- 概念与原理:
- AIO是一种真正的异步I/O模型。在AIO中,当线程发起一个I/O操作后,线程可以继续执行其他任务,而不需要等待I/O操作完成。当I/O操作完成后,系统会通过回调函数或者事件通知的方式来告知线程操作已经完成。这种方式进一步提高了系统的并发性能,因为线程完全不需要在I/O操作上等待。
- 代码示例(以Java AIO网络编程为例):
```java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;
- 概念与原理:
public class AIOServer {
public static void main(String[] args) {
try {
AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8080));
final CountDownLatch latch = new CountDownLatch(1);
System.out.println("服务器已启动,等待客户端连接...");
serverSocketChannel.accept(null, new CompletionHandler() {
@Override
public void completed(AsynchronousSocketChannel socketChannel, Object attachment) {
try {
serverSocketChannel.accept(null, this);
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.read(buffer, buffer, new CompletionHandler() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
if (result > 0) {
attachment.flip();
System.out.println("收到客户端消息:" + new String(attachment.array(), 0, result));
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
try {
latch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
});
latch.await();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
```
- 应用场景与优缺点:
- 应用场景:适用于对性能要求极高、处理大量并发I/O操作的场景,如大型分布式系统中的高性能网络通信、海量数据存储系统等。
- 优点:真正实现了I/O操作与线程执行的异步,最大限度地提高了系统的并发性能;通过回调函数或事件通知的方式,使得代码在处理I/O完成后的逻辑时更加灵活。
- 缺点:编程模型最复杂,需要对异步编程的概念和回调机制有深入的理解;不同操作系统对AIO的支持程度可能不同,可能会导致在某些系统上性能不如预期或者实现起来比较困难。