What is the difference between BIO, NIO and AIO?

BIO, NIO, and AIO are all I/O models in Java. Their main differences and simple demos are described below.

BIO (Blocking I/O)

BIO is Java’s earliest I/O model, also known as synchronous blocking I/O. In BIO, each I/O operation blocks the current thread and does not continue executing the next statement until the operation is completed, so it has poor concurrency.

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 {
            //Create ServerSocket and bind port
            ServerSocket serverSocket = new ServerSocket(8080);

            while (true) {
                // Listen for client connections
                Socket clientSocket = serverSocket.accept();
                System.out.println("Accepted connection from client");

                // Handle client request
                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;

        //Read the data sent by the client
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            String request = new String(buffer, 0, bytesRead);
            System.out.println("Received request: " + request);

            // Process the request and send the response to the client
            String response = "This is the response from server";
            outputStream.write(response.getBytes());
            outputStream.flush();
        }

        // Close the stream and connection
        inputStream.close();
        outputStream.close();
        clientSocket.close();
    }
}

The above is an example of a simple server using the blocking I/O model, which listens for client connections on port 8080 and sends a response after receiving a request.

Please note that the I/O operations in this example (inputStream.read() and outputStream.write()) are blocking, that is, when there is no data available When reading or writing, the thread will be blocked until data is available or the write is completed.

This is just a basic example. In actual applications, issues such as thread pools, multi-threading, and exception handling may need to be considered to improve performance and stability.

NIO (Non-blocking I/O)

NIO is a new I/O model introduced in Java 1.4, also known as synchronous non-blocking I/O. In NIO, the program polls registered channels through a selector. If a channel has data that can be read or written, corresponding processing will be performed. Because NIO supports multiplexing, a single thread can manage multiple channels simultaneously, improving concurrency performance.

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 {
            //Create ServerSocketChannel and bind the port
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(8080));
            serverSocketChannel.configureBlocking(false);

            //Create Selector and register Channel to Selector
            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            while (true) {
                // Listen for events
                selector.select();

                // Handle ready events
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectedKeys.iterator();

                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();

                    if (key.isAcceptable()) {
                        // Handle new connection requests
                        handleAcceptableEvent(serverSocketChannel, selector);
                    }

                    if (key.isReadable()) {
                        // Handle readable events
                        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) {
            // connection closed
            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);

            // handle the request
            String response = "This is the response from server";
            ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
            clientChannel.write(responseBuffer);
        }
    }
}

The above is an example of a simple server using the non-blocking I/O model, which listens for client connections on port 8080 and sends a response after receiving a request.

This example uses ServerSocketChannel to accept new connections and configures it in non-blocking mode. Then register ServerSocketChannel to Selector and specify to pay attention to the SelectionKey.OP_ACCEPT event.

In the event loop, first call selector.select() to listen for events, and then use an iterator to process ready events. For the OP_ACCEPT event, call the handleAcceptableEvent() method to handle the new connection request and register the new SocketChannel to the Selector on, and specify to pay attention to the SelectionKey.OP_READ event. For the OP_READ event, call the handleReadableEvent() method to read the data sent by the client and process the request.

It should be noted that non-blocking I/O under the NIO model needs to handle more details, such as buffer management, event selection and appropriate thread pools. Only a simple example is provided here. In actual applications, corresponding adjustments and optimizations may be required based on requirements.

AIO (Asynchronous I/O)

AIO is a new I/O model introduced in Java 1.7, also known as asynchronous non-blocking I/O. In AIO, when an I/O operation is performed, the operating system returns immediately and does not block the current thread. When the operation is completed, the operating system will notify the application, and then the application will process the data. Therefore, AIO can effectively utilize CPU time and improve concurrency performance.

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<AsynchronousSocketChannel, Void>() {
            @Override
            public void completed(AsynchronousSocketChannel clientChannel, Void attachment) {
                // Handle new connections
                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<Integer, 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);

                    // handle the request
                    String response = "This is the response from server";
                    ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                    clientChannel.write(responseBuffer, null, new CompletionHandler<Integer, 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();
            }
        });
    }
}

The above is an example of a simple server using the asynchronous I/O model, which listens for client connections on port 8080 and sends a response after receiving a request.

This example uses AsynchronousServerSocketChannel to accept new connections and configure it in asynchronous mode. Then, call the accept() method to receive the new connection, passing the CompletionHandler instance as a parameter, and handle the new connection request in the callback function. For an established connection, use the read() method to read the data sent by the client, pass the CompletionHandler instance as a parameter, and process the request in the callback function.

It should be noted that programming under the asynchronous I/O model is relatively complex and requires proficiency in the use of CompletionHandler, as well as how to manage buffers and event selection. Only a simple example is provided here. In actual applications, corresponding adjustments and optimizations may be required based on requirements.

To sum up, BIO, NIO, and AIO are all I/O models in Java. Their main difference lies in the way they handle I/O operations. BIO is a synchronous blocking model, and each I/O operation blocks the current thread; NIO is a synchronous non-blocking model, which implements multiplexing through selector polling registered channels, improving concurrency performance; AIO is an asynchronous non-blocking model, The operating system returns immediately and does not block the current thread, which can effectively utilize CPU time and further improve concurrency performance. Therefore, it is very important to choose the appropriate I/O model based on actual application scenarios and requirements.

For more news and information, please visit Ayshuju Data (https://www.ayshuju.com/home)