java IO模型
java IO模型
Java中的AIO、BIO、NIO是三种不同的I/O模型:
- BIO(Blocking I/O):同步阻塞I/O模型。在BIO模型中,应用程序发起I/O操作后,会一直阻塞等待I/O操作完成,期间不能进行其它任务。当I/O操作完成后,应用程序才能继续执行。BIO模型是Java早期的I/O API,使用了传统的同步I/O机制。BIO 是传统的阻塞式 I/O 模型,它以流的形式进行操作,每个连接都需要独立的线程来处理,当一个线程进行 I/O 操作时,它会一直阻塞直到数据准备好,这样就会造成线程数量的浪费。BIO 适用于连接数比较小的情况。
- NIO(Non-blocking I/O):同步非阻塞I/O模型。在NIO模型中,应用程序发起I/O操作后,不需要等待I/O操作完成,可以继续执行其它任务。但是在检查I/O操作完成状态时,仍然需要进行阻塞等待,直到I/O操作完成或者有数据可读取。NIO模型是Java 1.4中引入的新I/O API,使用了基于事件驱动的I/O机制。NIO 是一种基于事件驱动的 I/O 模型,它通过一个线程来处理多个连接,这样可以避免了线程数量的浪费。当一个连接有数据可读时,会触发一个事件通知线程,线程就可以处理该连接的数据。NIO 适用于连接数较多的情况。
- AIO(Asynchronous I/O):异步非阻塞I/O模型。在AIO模型中,应用程序发起I/O操作后,不需要等待I/O操作完成,而是可以继续执行其它任务。当I/O操作完成后,操作系统会通知应用程序进行后续处理。AIO模型是Java 7中引入的新I/O API,使用了操作系统的异步I/O机制。AIO 是 Java 7 中引入的一种异步 I/O 模型,它是基于 NIO 的,但是相比于 NIO,AIO 更加高级,可以实现异步读写操作。当一个 I/O 操作完成时,会触发一个回调函数,这样就可以实现异步处理。AIO 适用于连接数极多、连接时间较长、但数据交互量较小的情况。
相比于BIO模型,AIO和NIO模型能够支持更高的并发性能和更低的系统开销,因为它们能够利用操作系统的异步I/O机制或事件驱动机制,让应用程序更有效地利用CPU资源和I/O资源。但是,AIO和NIO模型的编程模型比BIO模型更复杂,需要更加深入的理解和掌握。
总之,BIO 适用于连接数比较小的情况,NIO 适用于连接数较多的情况,而 AIO 适用于连接数极多、连接时间较长、但数据交互量较小的情况。在实际应用中,应根据具体业务场景选择合适的 I/O 模型。
BIO
BIO介绍
同步阻塞I/O模型。在BIO模型中,应用程序发起I/O操作后,会一直阻塞等待I/O操作完成,期间不能进行其它任务。当I/O操作完成后,应用程序才能继续执行。BIO模型是Java早期的I/O API,使用了传统的同步I/O机制。
BIO 是传统的阻塞式 I/O 模型,它以流的形式进行操作,每个连接都需要独立的线程来处理,当一个线程进行 I/O 操作时,它会一直阻塞直到数据准备好,这样就会造成线程数量的浪费。BIO 适用于连接数比较小的情况。
BIO示例
import java.io.*;
import java.net.*;
public class BIOExample {
public static void main(String[] args) throws IOException {
// 创建ServerSocket对象,监听端口号为8888
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("Server started on port 8888.");
while (true) {
// 等待客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected from " + clientSocket.getRemoteSocketAddress());
// 从客户端读取数据
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = in.readLine();
System.out.println("Received message from client: " + message);
// 发送响应数据给客户端
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
out.println("Hello, client!");
// 关闭连接
clientSocket.close();
}
}
}
这是一个BIO例子,其中:
ServerSocket
对象用于创建服务器Socket,监听端口号为8888;- 通过
serverSocket.accept()
方法阻塞等待客户端连接; - 从客户端读取数据使用
BufferedReader
和InputStreamReader
,发送响应数据给客户端使用PrintWriter
; - 最后关闭连接。
NIO
NIO介绍
同步非阻塞I/O模型。在NIO模型中,应用程序发起I/O操作后,不需要等待I/O操作完成,可以继续执行其它任务。但是在检查I/O操作完成状态时,仍然需要进行阻塞等待,直到I/O操作完成或者有数据可读取。NIO模型是Java 1.4中引入的新I/O API,使用了基于事件驱动的I/O机制。
NIO 是一种基于事件驱动的 I/O 模型,它通过一个线程来处理多个连接,这样可以避免了线程数量的浪费。当一个连接有数据可读时,会触发一个事件通知线程,线程就可以处理该连接的数据。NIO 适用于连接数较多的情况。
NIO示例
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
public class NIOExample {
public static void main(String[] args) throws IOException {
// 创建ServerSocketChannel对象,监听端口号为8888
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8888));
serverSocketChannel.configureBlocking(false);
System.out.println("Server started on port 8888.");
// 创建Selector对象,用于监听事件
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 等待事件发生
selector.select();
for (SelectionKey key : selector.selectedKeys()) {
if (key.isAcceptable()) {
// 接受客户端连接
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverChannel.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Client connected from " + clientChannel.getRemoteAddress());
} else if (key.isReadable()) {
// 读取客户端数据
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = clientChannel.read(buffer);
if (bytesRead > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String message = new String(bytes, "UTF-8");
System.out.println("Received message from client: " + message);
// 发送响应数据给客户端
ByteBuffer responseBuffer = ByteBuffer.wrap("Hello, client!".getBytes("UTF-8"));
clientChannel.write(responseBuffer);
} else if (bytesRead < 0) {
clientChannel.close();
}
}
}
selector.selectedKeys().clear();
}
}
}
这是一个NIO例子,其中:
ServerSocketChannel
对象用于创建服务器Socket,监听端口号为8888;- 通过
Selector
对象监听事件; - 使用
SelectionKey
类来表示事件,包括OP_ACCEPT和OP_READ; - 在OP_ACCEPT事件中,接受客户端连接,并将客户端的SocketChannel注册到Selector中以监听读事件;
- 在OP_READ事件中,读取客户端数据,发送响应数据给客户端。
AIO
AIO介绍
异步非阻塞I/O模型。在AIO模型中,应用程序发起I/O操作后,不需要等待I/O操作完成,而是可以继续执行其它任务。当I/O操作完成后,操作系统会通知应用程序进行后续处理。AIO模型是Java 7中引入的新I/O API,使用了操作系统的异步I/O机制。
AIO 是 Java 7 中引入的一种异步 I/O 模型,它是基于 NIO 的,但是相比于 NIO,AIO 更加高级,可以实现异步读写操作。当一个 I/O 操作完成时,会触发一个回调函数,这样就可以实现异步处理。AIO 适用于连接数极多、连接时间较长、但数据交互量较小的情况。
AIO示例
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class AIOExample {
public static void main(String[] args) throws IOException {
// 创建AsynchronousServerSocketChannel对象,监听端口号为8888
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8888));
System.out.println("Server started on port 8888.");
// 注册Accept事件
serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel,IOException>() {
@Override
public void completed(AsynchronousSocketChannel clientChannel, Object attachment) {
// 接受客户端连接成功,注册Read事件
serverChannel.accept(null, this);
ByteBuffer buffer = ByteBuffer.allocate(1024);
clientChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
if (result > 0) {
attachment.flip();
byte[] bytes = new byte[attachment.remaining()];
attachment.get(bytes);
String message = new String(bytes, "UTF-8");
System.out.println("Received message from client: " + message);
// 发送响应数据给客户端
ByteBuffer responseBuffer = ByteBuffer.wrap("Hello, client!".getBytes("UTF-8"));
clientChannel.write(responseBuffer, responseBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
if (attachment.hasRemaining()) {
clientChannel.write(attachment, attachment, this);
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("Failed to send response to client.");
}
});
} else if (result < 0) {
try {
clientChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("Failed to read data from client.");
}
});
}
@Override
public void failed(Throwable exc, Object attachment) {
System.out.println("Failed to accept client connection.");
}
});
// 阻塞主线程
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这是一个AIO例子,其中:
AsynchronousServerSocketChannel
对象用于创建服务器Socket,监听端口号为8888;- 使用
CompletionHandler
回调函数来处理事件,包括Accept和Read事件; - 在Accept事件中,接受客户端连接,并将客户端的AsynchronousSocketChannel注册到Selector中以监听读事件;
- 在Read事件中,读取客户端数据,发送响应数据给客户端。