
BIO、NIO、AIO 都是 Java 中的 I/O 模型下面讲述他们的主要区别及其简单demo。BIOBlocking I/OBIO 是 Java 最早的 I/O 模型也称为同步阻塞 I/O。在 BIO 中每个 I/O 操作都会阻塞当前线程直到操作完成才会继续执行下一条语句因此它的并发性较差。import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class BlockingIOServer { public static void main(String[] args) { try { // 创建ServerSocket并绑定端口 ServerSocket serverSocket new ServerSocket(8080); while (true) { // 监听客户端连接 Socket clientSocket serverSocket.accept(); System.out.println(Accepted connection from client); // 处理客户端请求 handleClientRequest(clientSocket); } } catch (IOException e) { e.printStackTrace(); } } private static void handleClientRequest(Socket clientSocket) throws IOException { InputStream inputStream clientSocket.getInputStream(); OutputStream outputStream clientSocket.getOutputStream(); byte[] buffer new byte[1024]; int bytesRead; // 读取客户端发送的数据 while ((bytesRead inputStream.read(buffer)) ! -1) { String request new String(buffer, 0, bytesRead); System.out.println(Received request: request); // 处理请求并发送响应给客户端 String response This is the response from server; outputStream.write(response.getBytes()); outputStream.flush(); } // 关闭流和连接 inputStream.close(); outputStream.close(); clientSocket.close(); } }以上是一个使用阻塞I/O模型的简单服务器示例它会监听8080端口上的客户端连接并在接收到请求后发送响应。请注意该示例中的I/O操作inputStream.read()和outputStream.write()都是阻塞的也就是说当没有数据可读取或写入时线程将被阻塞直到有数据可用或写入完成。这只是一个基本的示例实际应用中可能需要考虑线程池、多线程处理和异常处理等方面的问题来提高性能和稳定性。NIONon-blocking I/ONIO 是 Java 1.4 引入的新 I/O 模型也称为同步非阻塞 I/O。在 NIO 中程序通过一个选择器Selector轮询注册的通道如果某个通道有数据可读或可写则进行相应的处理。由于 NIO 支持多路复用因此单个线程可以同时管理多个通道从而提高了并发性能。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 NonBlockingIOServer { public static void main(String[] args) { try { // 创建ServerSocketChannel并绑定端口 ServerSocketChannel serverSocketChannel ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(8080)); serverSocketChannel.configureBlocking(false); // 创建Selector并将Channel注册到Selector上 Selector selector Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { // 监听事件 selector.select(); // 处理就绪的事件 SetSelectionKey selectedKeys selector.selectedKeys(); IteratorSelectionKey iterator selectedKeys.iterator(); while (iterator.hasNext()) { SelectionKey key iterator.next(); if (key.isAcceptable()) { // 处理新的连接请求 handleAcceptableEvent(serverSocketChannel, selector); } if (key.isReadable()) { // 处理可读事件 handleReadableEvent(key); } iterator.remove(); } } } catch (IOException e) { e.printStackTrace(); } } private static void handleAcceptableEvent(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException { SocketChannel clientChannel serverSocketChannel.accept(); clientChannel.configureBlocking(false); clientChannel.register(selector, SelectionKey.OP_READ); System.out.println(Accepted connection from client); } private static void handleReadableEvent(SelectionKey key) throws IOException { SocketChannel clientChannel (SocketChannel) key.channel(); ByteBuffer buffer ByteBuffer.allocate(1024); int bytesRead clientChannel.read(buffer); if (bytesRead -1) { // 连接关闭 clientChannel.close(); return; } if (bytesRead 0) { buffer.flip(); byte[] requestData new byte[buffer.remaining()]; buffer.get(requestData); String request new String(requestData); System.out.println(Received request: request); // 处理请求 String response This is the response from server; ByteBuffer responseBuffer ByteBuffer.wrap(response.getBytes()); clientChannel.write(responseBuffer); } } }以上是一个使用非阻塞I/O模型的简单服务器示例它会监听8080端口上的客户端连接并在接收到请求后发送响应。这个示例中使用了ServerSocketChannel来接受新的连接并将其配置为非阻塞模式。然后将ServerSocketChannel注册到Selector上并指定关注SelectionKey.OP_ACCEPT事件。在事件循环中先调用selector.select()来监听事件然后使用迭代器处理就绪的事件。对于OP_ACCEPT事件调用handleAcceptableEvent()方法处理新连接请求并将新的SocketChannel注册到Selector上并指定关注SelectionKey.OP_READ事件。对于OP_READ事件调用handleReadableEvent()方法读取客户端发送的数据并处理请求。需要注意的是NIO模型下的非阻塞I/O需要处理更多的细节如缓冲区的管理、事件选择和合适的线程池等。这里只提供了一个简单的示例实际应用中可能需要根据需求做出相应的调整和优化。AIOAsynchronous I/OAIO 是 Java 1.7 引入的新 I/O 模型也称为异步非阻塞 I/O。在 AIO 中当进行 I/O 操作时操作系统会立即返回并不会阻塞当前线程。当操作完成后操作系统会通知应用程序然后再由应用程序对数据进行处理。因此AIO 可以有效地利用 CPU 时间提高并发性能。import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousChannelGroup; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.Executors; public class AsyncIOServer { private static final int PORT 8080; public static void main(String[] args) throws IOException { AsynchronousChannelGroup channelGroup AsynchronousChannelGroup.withThreadPool(Executors.newFixedThreadPool(10)); AsynchronousServerSocketChannel serverSocketChannel AsynchronousServerSocketChannel.open(channelGroup); serverSocketChannel.bind(new InetSocketAddress(PORT)); serverSocketChannel.accept(null, new CompletionHandlerAsynchronousSocketChannel, Void() { Override public void completed(AsynchronousSocketChannel clientChannel, Void attachment) { // 处理新的连接 serverSocketChannel.accept(null, this); handleClientChannel(clientChannel); } Override public void failed(Throwable exc, Void attachment) { exc.printStackTrace(); } }); } private static void handleClientChannel(AsynchronousSocketChannel clientChannel) { ByteBuffer buffer ByteBuffer.allocate(1024); clientChannel.read(buffer, null, new CompletionHandlerInteger, Void() { Override public void completed(Integer bytesRead, Void attachment) { if (bytesRead -1) { try { clientChannel.close(); } catch (IOException e) { e.printStackTrace(); } return; } if (bytesRead 0) { buffer.flip(); byte[] requestData new byte[buffer.remaining()]; buffer.get(requestData); String request new String(requestData); System.out.println(Received request: request); // 处理请求 String response This is the response from server; ByteBuffer responseBuffer ByteBuffer.wrap(response.getBytes()); clientChannel.write(responseBuffer, null, new CompletionHandlerInteger, Void() { Override public void completed(Integer bytesWritten, Void attachment) { if (responseBuffer.hasRemaining()) { clientChannel.write(responseBuffer, null, this); } else { try { clientChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } Override public void failed(Throwable exc, Void attachment) { exc.printStackTrace(); } }); } } Override public void failed(Throwable exc, Void attachment) { exc.printStackTrace(); } }); } }以上是一个使用异步I/O模型的简单服务器示例它会监听8080端口上的客户端连接并在接收到请求后发送响应。这个示例中使用了AsynchronousServerSocketChannel来接受新的连接并将其配置为异步模式。然后调用accept()方法来接收新的连接并将CompletionHandler实例作为参数传递并在回调函数中处理新连接请求。对于已经建立的连接使用read()方法读取客户端发送的数据并将CompletionHandler实例作为参数传递在回调函数中处理请求。需要注意的是异步I/O模型下的编程比较复杂需要熟练掌握CompletionHandler的使用以及如何管理缓冲区和事件选择等。这里只提供了一个简单的示例实际应用中可能需要根据需求做出相应的调整和优化。综上所述BIO、NIO、AIO 都是 Java 中的 I/O 模型它们的主要区别在于处理 I/O 操作的方式不同。BIO 是同步阻塞模型每个 I/O 操作都会阻塞当前线程NIO 是同步非阻塞模型通过选择器轮询注册的通道实现多路复用提高了并发性能AIO 是异步非阻塞模型操作系统立即返回并不会阻塞当前线程可以有效地利用 CPU 时间进一步提高并发性能。因此根据实际应用场景和需求选择合适的 I/O 模型非常重要。