Java NIO 非阻塞模式(Non-blocking mode)讲解和实战demo

Java NIO(Non-blocking I/O)提供了一种非阻塞I/O的实现方式,使得一个线程可以管理多个通道。相比于传统的I/O,非阻塞I/O可以更好地处理高并发的情况,提高系统的吞吐量。

非阻塞I/O的实现方式是将通道设置为非阻塞模式,这样当通道没有准备好读或写时,不会一直阻塞等待,而是立即返回。这样线程就可以继续执行其他操作,等通道准备好后再进行读写操作。在非阻塞模式下,读写操作需要在一个循环中不断进行,直到完成所有操作。

Java NIO中,通道必须在非阻塞模式下才能使用选择器(Selector)。选择器可以用来监听多个通道的事件,比如读就绪、写就绪等,从而避免了阻塞模式下每个通道都需要一个线程进行监听的问题。使用选择器可以大大提高系统的并发处理能力。

下面是一个简单的Java NIO非阻塞模式的示例代码:

public class NonBlockingServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress("localhost", 8080));
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            selector.select();
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                if (key.isAcceptable()) {
                    SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int bytesRead = socketChannel.read(buffer);
                    if (bytesRead == -1) {
                        socketChannel.close();
                        continue;
                    }
                    buffer.flip();
                    String message = new String(buffer.array(), 0, bytesRead);
                    System.out.println("Received message: " + message);
                }
            }
        }
    }
}

这段代码实现了一个简单的非阻塞模式的服务器,可以接收客户端的连接请求,并读取客户端发送的数据。在代码中,我们首先将服务器通道设置为非阻塞模式,并注册到选择器上,监听OP_ACCEPT事件。然后使用循环来等待事件发生,当有事件发生时,我们遍历选择器的事件集合,根据事件类型进行不同的操作。如果是OP_ACCEPT事件,则接受客户端的连接请求,并将客户端通道注册到选择器上,监听OP_READ事件。如果是OP_READ事件,则读取客户端发送的数据。

在非阻塞模式下,通道和选择器的使用可以更加灵活和高效。