BIO、NIO、AIO 有什么区别

        BIO、NIO、AIO 都是 Java 中的 I/O 模型,下面讲述他们的主要区别,及其简单demo。

BIO(Blocking I/O)

        BIO 是 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())都是阻塞的,也就是说当没有数据可读取或写入时,线程将被阻塞,直到有数据可用或写入完成。

        这只是一个基本的示例,实际应用中可能需要考虑线程池、多线程处理和异常处理等方面的问题来提高性能和稳定性。

NIO(Non-blocking I/O)

        NIO 是 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();

                // 处理就绪的事件
                Set selectedKeys = selector.selectedKeys();
                Iterator 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需要处理更多的细节,如缓冲区的管理、事件选择和合适的线程池等。这里只提供了一个简单的示例,实际应用中可能需要根据需求做出相应的调整和优化。

AIO(Asynchronous I/O)

        AIO 是 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 CompletionHandler() {
            @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 CompletionHandler() {
            @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 CompletionHandler() {
                        @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 模型非常重要。

更多消息资讯,请访问昂焱数据(https://www.ayshuju.com/home)

你可能感兴趣的:(nio)