Java中的BIO, NIO和AIO: 三者的主要差异
发表时间: 2024-05-26 01:31
在面试中,BIO、NIO 和 AIO 是 Java IO 模型中经常被问到的知识点。理解它们之间的区别、工作原理以及应用场景,对于一个资深的 Java 开发者来说是非常重要的。
BIO 模型是最传统的 Java I/O 模型,基于阻塞流的方式进行数据读写操作。每个连接都会占用一个独立的线程,当连接数量增加时,会导致线程数量急剧增加,进而影响系统性能。
工作原理:
示例代码:
java
import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;public class BIOServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8080); System.out.println("BIO Server started, listening on port 8080"); while (true) { // 阻塞等待客户端连接 Socket socket = serverSocket.accept(); new Thread(new ClientHandler(socket)).start(); } }}class ClientHandler implements Runnable { private Socket socket; public ClientHandler(Socket socket) { this.socket = socket; } @Override public void run() { try { // 读/写操作 InputStream input = socket.getInputStream(); OutputStream output = socket.getOutputStream(); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = input.read(buffer)) != -1) { output.write(buffer, 0, bytesRead); } } catch (IOException e) { e.printStackTrace(); } finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } }}
适用场景:
NIO 模型引入了非阻塞 IO 操作,通过选择器(Selector)管理多个通道(Channel),实现高效地处理大量连接。NIO 提供了缓冲区(Buffer)和选择器(Selector)等重要概念。
工作原理:
示例代码:
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;public class NIOServer { public static void main(String[] args) throws IOException { Selector selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(8080)); serverSocketChannel.configureBlocking(false); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("NIO Server started, listening on port 8080"); while (true) { selector.select(); Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if (key.isAcceptable()) { handleAccept(key); } else if (key.isReadable()) { handleRead(key); } } } } private static void handleAccept(SelectionKey key) throws IOException { ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(key.selector(), SelectionKey.OP_READ); } private static void handleRead(SelectionKey key) throws IOException { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = socketChannel.read(buffer); if (bytesRead > 0) { buffer.flip(); socketChannel.write(buffer); } else if (bytesRead == -1) { socketChannel.close(); } }}
适用场景:
AIO 模型是 JDK 7 引入的一种异步 IO 模型,提供了异步通道(AsynchronousSocketChannel)和异步文件通道(AsynchronousFileChannel)。AIO 模型可以在操作完成时通过回调函数通知应用程序,从而实现更高效的 IO 操作。
工作原理:
示例代码:
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) throws IOException { AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(8080)); System.out.println("AIO Server started, listening on port 8080"); CountDownLatch latch = new CountDownLatch(1); serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() { @Override public void completed(AsynchronousSocketChannel result, Object attachment) { serverSocketChannel.accept(null, this); handleClient(result); } @Override public void failed(Throwable exc, Object attachment) { exc.printStackTrace(); latch.countDown(); } }); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } private static void handleClient(AsynchronousSocketChannel channel) { ByteBuffer buffer = ByteBuffer.allocate(1024); channel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { attachment.flip(); channel.write(attachment, attachment, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { attachment.clear(); channel.read(attachment, attachment, this); } @Override public void failed(Throwable exc, ByteBuffer attachment) { exc.printStackTrace(); try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } }); } @Override public void failed(Throwable exc, ByteBuffer attachment) { exc.printStackTrace(); try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } }); }}
适用场景:
通过理解 BIO、NIO 和 AIO 的工作原理和应用场景,开发者可以根据具体需求选择合适的 IO 模型,从而优化系统性能和提高开发效率。