NIO、BIO 和 AIO 是 Java 编程中常用的 I/O 模型,它们的主要区别在于它们处理 I/O 操作的方式不同。下面是对它们的简要描述和 Java 代码实例:
1.BIO (Blocking I/O)
BIO 是 Java 中最早的 I/O 模型,也是最简单的一种模型,它是阻塞 I/O,即在进行网络通信时,读写操作会阻塞当前线程,直到操作完成或者超时才会返回结果。BIO 的主要特点是:每个客户端请求都需要创建一个独立的线程,服务器线程在处理请求时会阻塞,直到客户端发送数据并且将其读取完成之后才会进行下一步操作。
下面是一个使用 BIO 的示例代码:
ServerSocket serverSocket = new ServerSocket(8080);
while(true){
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
byte[] buffer = new byte[1024];
int length = inputStream.read(buffer);
String request = new String(buffer,0,length);
String response = "Hello, " + request + "\n";
outputStream.write(response.getBytes());
socket.close();
}
2.NIO (Non-Blocking I/O)
NIO 是 Java 中新增的 I/O 模型,它采用了多路复用的方式来处理 I/O 操作,即使用一个线程来处理多个请求。NIO 的主要特点是:所有的 I/O 操作都是非阻塞的,线程可以处理多个请求,而不是像 BIO 那样每个请求都需要一个线程。
下面是一个使用 NIO 的示例代码:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true){
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while(iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
if(selectionKey.isAcceptable()){
ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = channel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}else if(selectionKey.isReadable()){
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int length = socketChannel.read(buffer);
String request = new String(buffer.array(),0,length);
String response = "Hello, " + request + "\n";
ByteBuffer writeBuffer = ByteBuffer.wrap(response.getBytes());
socketChannel.write(writeBuffer);
socketChannel.close();
}
iterator.remove();
}
}
3.AIO (Asynchronous I/O)
AIO 是 Java 中较新的 I/O 模型,它在 NIO 的基础上进一步封装,提供了更为方便的异步 I/O 操作接口。AIO 的主要特点是:所有的 I/O 操作都是异步的,即当一个操作完成时,会通知应用程序进行处理,而不需要等待操作完成再返回结果。AIO 适用于高并发的场景,它的性能比 NIO 更高。
下面是一个使用 AIO 的示例代码:
AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel socketChannel, Void attachment) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
attachment.flip();
String request = new String(attachment.array(), 0, result);
String response = "Hello, " + request + "\n";
ByteBuffer writeBuffer = ByteBuffer.wrap(response.getBytes());
socketChannel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
try {
socketChannel.close();
serverSocketChannel.accept(null, this);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
在上面的示例代码中,使用了 AsynchronousServerSocketChannel 类和 CompletionHandler 接口来实现异步的 I/O 操作。当有客户端连接时,会调用 accept() 方法来接收连接,并在回调函数中进行读取和写入操作,当操作完成时,会再次调用 accept() 方法来接收下一个连接。这种方式可以在不阻塞线程的情况下处理多个请求,提高了应用程序的并发能力。